home *** CD-ROM | disk | FTP | other *** search
/ MacFormat España 22 / macformat_22.iso / Shareware / Programación / The Gray Council 1.1 / source / Core / GrayCouncil.cpp next >
Encoding:
Text File  |  1996-08-08  |  200.6 KB  |  8,361 lines  |  [TEXT/CWIE]

  1. //
  2. // GrayCouncil
  3. // Copyright ©1996 by Trygve Isaacson. All Rights Reserved.
  4. //
  5. // Before using any of the GrayCouncil source code, read and
  6. // follow the licensing info in the accompanying documentation
  7. // or contact:
  8. //   <trygve@kagi.com>
  9. //   <http://www.kagi.com/authors/trygve/>
  10. //
  11. // GrayCouncil provides a set of standard C++ classes that implement
  12. // the standard Apple Grayscale Appearance. The core classes do not
  13. // require any other code such as a particular class framework.
  14. // There are separate files provided that plug the GrayCouncil core
  15. // into class frameworks.
  16. //
  17. // Classes defined below:
  18. //    AGAObject -- abstract base class for most others
  19. //    MExclusiveObject -- mixin class for mutual exclusivity (e.g. radio)
  20. //    AGATextStyle -- text style attributes container
  21. //    AGAStaticText -- simple string object
  22. //    AGAPushButton -- push button with auto default outline capability
  23. //    AGACheckBox -- check box with mixed state capability
  24. //    AGARadioButton -- radio button with mixed state capability
  25. //    MIconButtonObject -- mixin class for icon buttons
  26. //    AGAIconPushButton -- AGAPushButton subclass for icon push buttons
  27. //    AGAIconCheckBox -- AGACheckBox subclass for on/off icon buttons
  28. //    AGAIconRadioButton -- AGARadioButton subclass for mutually exclusive
  29. //        on/off icon buttons
  30. //    AGATrackingIndicator -- abstract superclass for scroll bar and slider
  31. //    AGAScrollBar -- scroll bar with 32-bit values, live tracking, and
  32. //        proportional indicator capabilities
  33. //    AGASlider -- slider with pointy or rectangular indicator, optional
  34. //        labels, live tracking, proportional indicator capabilities
  35. //    AGAPopupMenu -- popup menu with optional title
  36. //    AGALittleArrows -- little up/down arrows with notification
  37. //    AGADisclosureTriangle -- disclosure triangle with animation
  38. //    AGAProgressIndicator -- determinate or indeterminate progress gauge
  39. //        with moving determinate origin capability
  40. //    AGASeparator -- separator line with automatic directionality
  41. //    AGAGroupBox -- primary or secondary group box with optional title or
  42. //        room for external title or control
  43. //
  44.  
  45. #include "GrayCouncil.h"
  46.  
  47. #include <limits.h>
  48. #include <plstringfuncs.h>
  49.  
  50. //
  51. // Global variables ---------------------------------------------------
  52. //
  53.  
  54. const Str255 gGrayCouncilCopyright = kGrayCouncilCopyright;
  55.  
  56. Boolean gAGAHasColorQD;
  57.  
  58. UInt32    gAGADefaults = 0;
  59.  
  60. // This is global group maintainer.
  61. static AGAGroupsContainer* gGroupsContainer;
  62.  
  63. // Standard system text style, used by most standard controls.
  64. AGATextStyle gAGAStdSystemStyle = AGATextStyle();
  65.  
  66. // Standard small text style, used for slider labels.
  67. AGATextStyle gAGAStdSmallStyle = AGATextStyle(applFont, 10, normal);
  68.  
  69. // Extra small text style, a de facto standard.
  70. AGATextStyle gAGAExtraSmallStyle = AGATextStyle(applFont, 9, normal);
  71.  
  72. // These are the AGA-specified color values.
  73. RGBColor gAGARamp[kNumRampColors] =
  74.     {
  75.     {65535, 65535, 65535},    // rW    white
  76.     {61166, 61166, 61166},    // r1    lightest gray
  77.     {56797, 56797, 56797},    // r2
  78.     {52428, 52428, 52428},    // r3
  79.     {48059, 48059, 48059},    // r4    light grays
  80.     {43690, 43690, 43690},    // r5
  81.     {39321, 39321, 39321},    // r6
  82.     {34952, 34952, 34952},    // r7
  83.     {30583, 30583, 30583},    // r8    dark grays
  84.     {26214, 26214, 26214},    // r9
  85.     {21845, 21845, 21845},    // r10
  86.     {17476, 17476, 17476},    // r11
  87.     {8738, 8738, 8738},        // r12    darkest gray
  88.     {13107, 13107, 13107},    // rA    additional gray value
  89.     {0, 0, 0},                // rB    black
  90.     {52428, 52428, 65535},    // rA1    lightest purple
  91.     {39321, 39321, 65535},    // rA2    light purple
  92.     {26214, 26214, 65535},    // rA3    dark purple
  93.     {13107, 13107, 26214}    // rA4    darkest purple
  94.     };
  95.  
  96. //
  97. // Initialization -----------------------------------------------------
  98. //
  99. // Must be called by client application after initializing the toolbox,
  100. // and before any other Gray Council calls are made.
  101. // The framework-specific initialization functions call this automatically.
  102. //
  103.  
  104. OSErr InitGrayCouncil()
  105.     {
  106.     OSErr    result;
  107.     SInt32    gestaltResponse;
  108.  
  109.     //
  110.     // Initialize some basic globals.
  111.     //
  112.     
  113.     // Default flags. Only live scrolling is on by default.
  114.     gAGADefaults = kAGALiveScrolling;
  115.     
  116.     // Set global Color QuickDraw flag.
  117.     result = ::Gestalt(gestaltQuickdrawVersion, &gestaltResponse);
  118.     gAGAHasColorQD = (result == noErr) && (gestaltResponse != gestaltOriginalQD);
  119.     
  120.     // Allocate the group container.
  121.     gGroupsContainer = new AGAGroupsContainer;
  122.  
  123.     // Try to allocate the offscreen images.
  124.     result = AGARadioButton::AllocateRadioImages();
  125.     result = AGAProgressIndicator::AllocateProgressImages();
  126.     
  127.     return result;
  128.     }
  129.  
  130. #pragma segment GrayCouncilCore1
  131.  
  132. //
  133. // Static routines used only inside this file -------------------------
  134. //
  135.  
  136. static SInt16 MinSInt16(SInt16 a, SInt16 b) { return (a < b) ? a : b; }
  137. static SInt16 MaxSInt16(SInt16 a, SInt16 b) { return (a > b) ? a : b; }
  138. static SInt32 MinSInt32(SInt32 a, SInt32 b) { return (a < b) ? a : b; }
  139. static SInt32 MaxSInt32(SInt32 a, SInt32 b) { return (a > b) ? a : b; }
  140.  
  141. static void DelayFuture(SInt32 delayTicks)
  142.     {
  143.     // Delay for the specified number of ticks.
  144.  
  145.     SInt32    dontCare;
  146.     ::Delay(delayTicks, &dontCare);
  147.     }
  148.  
  149. static void DelayFutureWhileStillDown(SInt32 delayTicks)
  150.     {
  151.     // Delay for the specified number of ticks, but bail
  152.     // out if the user lets go of the mouse first.
  153.  
  154.     SInt32    future = delayTicks + ::TickCount();
  155.  
  156.     while (::StillDown() && (::TickCount() < future))
  157.         {};
  158.     }
  159.  
  160. static SInt32 RuntimeJustify(SInt32 userJust)
  161.     {
  162.     // Return the actual runtime justification value for
  163.     // the supplied value. The caller can use the result
  164.     // alone to know determine drawing direction.
  165.     // If the supplied value specifies default, we need
  166.     // to check the current system script direction.
  167.     // Otherwise, whatever was specified is OK as is.
  168.  
  169.     if (userJust == teFlushDefault)
  170.         {
  171.         if (::GetSysDirection() == 0)
  172.             return teFlushLeft;
  173.         else
  174.             return teFlushRight;
  175.         }
  176.     else
  177.         return userJust;
  178.     }
  179.  
  180. //
  181. // AGATextStyle --------------------------------------------------------
  182. //
  183.  
  184. AGATextStyle::AGATextStyle()
  185.     {
  186.     // Default constructor, use system font.
  187.  
  188.     mFontNum = systemFont;    // typically Chicago
  189.     mFontSize = 0;            // application size, typically 12-point
  190.     mFontStyle = normal;
  191.     }
  192.  
  193. AGATextStyle::AGATextStyle(SInt16 fontNum, SInt16 fontSize, Style fontStyle)
  194.     {
  195.     // Construct with direct parameters.
  196.  
  197.     mFontNum = fontNum;
  198.     mFontSize = fontSize;
  199.     mFontStyle = fontStyle;
  200.     }
  201.  
  202. AGATextStyle::AGATextStyle(StringPtr fontName, SInt16 fontSize, Style fontStyle)
  203.     {
  204.     // Construct by converting font name to font number.
  205.  
  206.     ::GetFNum(fontName, &mFontNum);
  207.     mFontSize = fontSize;
  208.     mFontStyle = fontStyle;
  209.     }
  210.  
  211. AGATextStyle::AGATextStyle(const TextStyle& textStyle)
  212.     {
  213.     // Construct by copying another text style.
  214.  
  215.     mFontNum = textStyle.tsFont;
  216.     mFontSize = textStyle.tsSize;
  217.     mFontStyle = textStyle.tsFace;
  218.     }
  219.  
  220. #ifdef __PowerPlant__
  221. AGATextStyle::AGATextStyle(ResIDT inTextTraitsID)
  222.     {
  223.     // Construct from a PowerPlant Text Traits resource.
  224.  
  225.     TextTraitsH aTTHandle = UTextTraits::LoadTextTraits(inTextTraitsID);
  226.     
  227.     if (aTTHandle == NULL)    // likely, cos there is no "0" Txtr resource
  228.         {
  229.         mFontNum = systemFont;    // typically Chicago
  230.         mFontSize = 0;            // application size, typically 12-point
  231.         mFontStyle = normal;
  232.         }
  233.     else
  234.         {
  235.         mFontNum = (**aTTHandle).fontNumber;
  236.         mFontSize = (**aTTHandle).size;
  237.         mFontStyle = (**aTTHandle).style;
  238.         
  239.         if (mFontNum == UTextTraits::fontNumber_Unknown) // means use supplied font name
  240.             {
  241.             Str255    fontName;
  242.             
  243.             PLstrcpy(fontName, (**aTTHandle).fontName);
  244.             ::GetFNum(fontName, &mFontNum);
  245.             }
  246.         }
  247.     }
  248. #endif // __PowerPlant__
  249.  
  250. void AGATextStyle::PrepareForDrawing() const
  251.     {
  252.     // Set the text pen for subsequent drawing.
  253.  
  254.     ::TextFont(mFontNum);
  255.     ::TextSize(mFontSize);
  256.     ::TextFace(mFontStyle);
  257.     }
  258.  
  259. //
  260. // AGAObject ---------------------------------------------------------------
  261. //
  262.  
  263. AGAObject::AGAObject(Rect* bounds)
  264.     {
  265.     // Construct enabled.
  266.  
  267.     mBounds = *bounds;
  268.     mEnabled = TRUE;
  269.     mBackgroundEraseColor = gAGARamp[r2];
  270.     }
  271.  
  272. AGAObject::~AGAObject()
  273.     {
  274.     }
  275.  
  276. void AGAObject::GetObjectBounds(Rect* bounds)
  277.     {
  278.     // Return current bounds.
  279.  
  280.     *bounds = mBounds;
  281.     }
  282.  
  283. void AGAObject::SetObjectBounds(Rect* bounds, Boolean redraw)
  284.     {
  285.     // Change bounds, redraw if specified.
  286.  
  287.     mBounds = *bounds;
  288.     
  289.     if (redraw)
  290.         this->DrawObject();
  291.     }
  292.  
  293. void AGAObject::DrawObject()
  294.     {
  295.     // Override to draw particular type of object.
  296.     }
  297.  
  298. Boolean AGAObject::ContainsMouse(Point mouseLocation)
  299.     {
  300.     // Return true if mouse will hit object.
  301.  
  302.     return ::PtInRect(mouseLocation, &mBounds);
  303.     }
  304.  
  305. Boolean AGAObject::TrackMouse(Point mouseLocation)
  306.     {
  307.     // Process mouse tracking, return true if tracking
  308.     // eventually "did something". Return false if
  309.     // tracking had no ultimate effect, e.g. mouse
  310.     // up outside a push button.
  311.  
  312.     Boolean    finishedIn = FALSE;
  313.     Boolean    wasIn = FALSE;
  314.     Boolean    isIn;
  315.     Boolean    isButtonDown = TRUE;    // ensure at least one time through
  316.     Point    newMouseLocation;
  317.     
  318.     while (isButtonDown)
  319.         {
  320.         ::GetMouse(&newMouseLocation);    // gives local coordinates
  321.         
  322.         isIn = this->HitTest(newMouseLocation);
  323.         
  324.         if (isIn != wasIn)
  325.             this->SetTrackingState(isIn);
  326.         
  327.         wasIn = isIn;
  328.  
  329.         isButtonDown = ::StillDown();
  330.         }
  331.     
  332.     if (isIn)    // if finished IN, restore normal appearance
  333.         this->SetTrackingState(kTrackingOut);
  334.     
  335.     return isIn;
  336.     }
  337.  
  338. void AGAObject::SetEnable(Boolean isEnabled, Boolean redraw)
  339.     {
  340.     // Set object enable state, redraw if specified.
  341.  
  342.     mEnabled = isEnabled;
  343.     
  344.     if (redraw)
  345.         this->DrawObject();
  346.     }
  347.  
  348. void AGAObject::SetBackgroundEraseColor(RGBColor* color)
  349.     {
  350.     // Set color to be used when erasing background.
  351.     // Most views don't need this. Default is AGA ramp r2.
  352.     // AGAStaticText and AGADisclosureTriangle need to
  353.     // erase their background, so if your background is
  354.     // not r2 (white, for example), call this to set it.
  355.  
  356.     mBackgroundEraseColor = *color;
  357.     }
  358.  
  359. Boolean AGAObject::HitTest(Point mouseLocation)
  360.     {
  361.     // Return true if mouse is inside tracking area of
  362.     // object. This function may be overridden for
  363.     // classes that do not have simple rectangular
  364.     // boundary hit testing.
  365.  
  366.     return ::PtInRect(mouseLocation, &mBounds);
  367.     }
  368.  
  369. void AGAObject::SetTrackingState(Boolean isIn)
  370.     {
  371.     // Override to draw the object in the appropriate
  372.     // state during tracking. If isIn is true, it means
  373.     // that the mouse is now in the positive hit test
  374.     // area of the object.
  375.     }
  376.  
  377. //
  378. // AGAStaticText ---------------------------------------------------------------
  379. //
  380. // This class draws a static text label.
  381. //
  382.  
  383. AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification)
  384. : AGAObject(bounds)
  385.     {
  386.     // Construct with empty string.
  387.  
  388.     mJustification = justification;
  389.     mTitle[0];
  390.     mTextStyle = textStyle;
  391.     }
  392.  
  393. AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification, StringPtr title)
  394. : AGAObject(bounds)
  395.     {
  396.     // Construct with supplied string.
  397.  
  398.     mJustification = justification;
  399.     PLstrcpy(mTitle, title);
  400.     mTextStyle = textStyle;
  401.     }
  402.  
  403. AGAStaticText::AGAStaticText(Rect* bounds, const AGATextStyle& textStyle, SInt32 justification, SInt16 stringListResourceID, SInt16 stringIndex)
  404. : AGAObject(bounds)
  405.     {
  406.     // Construct by getting string from specified resource.
  407.  
  408.     mJustification = justification;
  409.     ::GetIndString(mTitle, stringListResourceID, stringIndex);
  410.     mTextStyle = textStyle;
  411.     }
  412.  
  413. AGAStaticText::~AGAStaticText()
  414.     {
  415.     }
  416.  
  417. void AGAStaticText::DrawObject()
  418.     {
  419.     CleansePen();
  420.  
  421.     // Paint gray over possible obsolete text, draw current text.
  422.  
  423.     GDIterator    iter;
  424.     Boolean        deep;
  425.  
  426.     while (iter.More(deep))
  427.         {
  428.         if (deep)
  429.             ::RGBForeColor(&mBackgroundEraseColor);
  430.         else
  431.             ::RGBForeColor(&gAGARamp[rW]);
  432.  
  433.         ::PaintRect(&mBounds);
  434.  
  435.         AGAStringOut(mTitle, &mBounds, truncEnd, mJustification, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle);
  436.         }
  437.  
  438.     CleansePen();
  439.     }
  440.  
  441. void AGAStaticText::SetTitle(StringPtr title, Boolean redraw)
  442.     {
  443.     // Change text, redraw if specified.
  444.  
  445.     PLstrcpy(mTitle, title);
  446.     
  447.     if (redraw)
  448.         this->DrawObject();
  449.     }
  450.  
  451. //
  452. // AGAPushButton ---------------------------------------------------------------
  453. //
  454. // This class implements a standard text pushbutton object.
  455. //
  456.  
  457. AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle)
  458. : AGAObject(bounds)
  459.     {
  460.     // Construct with initial empty button title.
  461.  
  462.     mIsDefault = FALSE;
  463.     mFrameInside = TRUE;
  464.     mTitle[0];
  465.     mTextStyle = textStyle;
  466.     }
  467.  
  468. AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle, StringPtr title)
  469. : AGAObject(bounds)
  470.     {
  471.     // Construct with specified button title.
  472.  
  473.     mIsDefault = FALSE;
  474.     mFrameInside = TRUE;
  475.     PLstrcpy(mTitle, title);
  476.     mTextStyle = textStyle;
  477.     }
  478.  
  479. AGAPushButton::AGAPushButton(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex)
  480. : AGAObject(bounds)
  481.     {
  482.     // Construct by getting button title from specified resource.
  483.  
  484.     mIsDefault = FALSE;
  485.     mFrameInside = TRUE;
  486.     ::GetIndString(mTitle, stringListResourceID, stringIndex);
  487.     mTextStyle = textStyle;
  488.     }
  489.  
  490. AGAPushButton::~AGAPushButton()
  491.     {
  492.     }
  493.  
  494. void AGAPushButton::DrawObject()
  495.     {
  496.     // Draw button in normal unpressed state.
  497.  
  498.     this->DrawButton(kNotPressed);
  499.     }
  500.  
  501. void AGAPushButton::SetTitle(StringPtr title, Boolean redraw)
  502.     {
  503.     // Change button title, redraw if specified.
  504.  
  505.     PLstrcpy(mTitle, title);
  506.     
  507.     if (redraw)
  508.         this->DrawObject();
  509.     }
  510.  
  511. void AGAPushButton::SetDefault(Boolean isDefault, Boolean frameInside)
  512.     {
  513.     // Set default state. If mIsDefault is true, the button will
  514.     // be drawn with a default button outline. If mFrameInside
  515.     // is true, the outline will be inside mBounds and the button
  516.     // will be drawn inset from there; if mFrameInside is false,
  517.     // the outline will be outside mBounds and the button will
  518.     // be drawn at mBounds.
  519.  
  520.     mIsDefault = isDefault;
  521.     mFrameInside = frameInside;
  522.     }
  523.  
  524. void AGAPushButton::DrawButton(Boolean pressed)
  525.     {
  526.     CleansePen();
  527.  
  528.     // Draw the button in the appropriate state.
  529.  
  530.     GDIterator    iter;
  531.     Boolean        deep;
  532.  
  533.     while (iter.More(deep))
  534.         {
  535.         if (! mEnabled)
  536.             this->DrawButtonDisabled(deep);
  537.         else if (pressed)
  538.             this->DrawButtonPressed(deep);
  539.         else
  540.             this->DrawButtonNormal(deep);
  541.         }
  542.  
  543.     CleansePen();
  544.     }
  545.  
  546. Boolean AGAPushButton::HitTest(Point mouseLocation)
  547.     {
  548.     // Return true if the mouse is in the button.
  549.     // Account for case where default button outline
  550.     // is inside mBounds.
  551.  
  552.     Rect    r = mBounds;
  553.     
  554.     if (mIsDefault && mFrameInside)
  555.         ::InsetRect(&r, 3, 3);
  556.  
  557.     return ::PtInRect(mouseLocation, &r);
  558.     }
  559.  
  560. void AGAPushButton::SetTrackingState(Boolean isIn)
  561.     {
  562.     // Draw the button pressed or unpressed as specified.
  563.  
  564.     this->DrawButton(isIn);
  565.     }
  566.  
  567. void AGAPushButton::DrawButtonNormal(Boolean deep)
  568.     {
  569.     // Draw the button in enabled/unpressed state.
  570.  
  571.     Rect    r = mBounds;
  572.     
  573.     if (mIsDefault && mFrameInside)
  574.         ::InsetRect(&r, 3, 3);
  575.     
  576.     ::PenSize(1, 1);
  577.  
  578.     if (deep)
  579.         {
  580.         // Fill the interior.
  581.         ::InsetRect(&r, 1, 1);
  582.         ::RGBForeColor(&gAGARamp[r2]);
  583.         ::PaintRect(&r);
  584.         ::InsetRect(&r, -1, -1);
  585.         
  586.         // Draw the frame.
  587.         ::MoveTo(r.left + 1, r.top + 1);
  588.         ::RGBForeColor(&gAGARamp[rB]);
  589.         ::Line(0, 0);
  590.         ::Move(1, -1);
  591.         ::RGBForeColor(&gAGARamp[r12]);
  592.         ::Line(0, 0);
  593.         ::Move(1, 0);
  594.         ::RGBForeColor(&gAGARamp[rB]);
  595.         ::Line(r.right - r.left - 6, 0);
  596.         ::RGBForeColor(&gAGARamp[r12]);
  597.         ::Line(0, 0);
  598.         ::Move(1, 1);
  599.         ::RGBForeColor(&gAGARamp[rB]);
  600.         ::Line(0, 0);
  601.         ::Move(1, 1);
  602.         ::RGBForeColor(&gAGARamp[r12]);
  603.         ::Line(0, 0);
  604.         ::Move(0, 1);
  605.         ::RGBForeColor(&gAGARamp[rB]);
  606.         ::Line(0, r.bottom - r.top - 6);
  607.         ::RGBForeColor(&gAGARamp[r12]);
  608.         ::Line(0, 0);
  609.         ::Move(-1, 1);
  610.         ::RGBForeColor(&gAGARamp[rB]);
  611.         ::Line(0, 0);
  612.         ::Move(-1, 1);
  613.         ::RGBForeColor(&gAGARamp[r12]);
  614.         ::Line(0, 0);
  615.         ::Move(-1, 0);
  616.         ::RGBForeColor(&gAGARamp[rB]);
  617.         ::Line(- (r.right - r.left - 6), 0);
  618.         ::RGBForeColor(&gAGARamp[r12]);
  619.         ::Line(0, 0);
  620.         ::Move(-1, -1);
  621.         ::RGBForeColor(&gAGARamp[rB]);
  622.         ::Line(0, 0);
  623.         ::Move(-1, -1);
  624.         ::RGBForeColor(&gAGARamp[r12]);
  625.         ::Line(0, 0);
  626.         ::Move(0, -1);
  627.         ::RGBForeColor(&gAGARamp[rB]);
  628.         ::Line(0, -(r.bottom - r.top - 6));
  629.         ::RGBForeColor(&gAGARamp[r12]);
  630.         ::Line(0, 0);
  631.         
  632.         // Add 1st inner pixels.
  633.         ::MoveTo(r.left + 1, r.top + 2);
  634.         ::RGBForeColor(&gAGARamp[r4]);
  635.         ::Line(0, 0);
  636.         ::Move(1, -1);
  637.         ::Line(0, 0);
  638.         ::Move(r.right - r.left - 5, 0);
  639.         ::Line(0, 0);
  640.         ::Move(1, 1);
  641.         ::RGBForeColor(&gAGARamp[r5]);
  642.         ::Line(0, 0);
  643.         ::Move(0, 1);
  644.         ::RGBForeColor(&gAGARamp[r8]);
  645.         ::Line(0, r.bottom - r.top - 6);
  646.         ::Line(-1, 0);
  647.         ::Line(0, 1);
  648.         ::Line(- (r.right - r.left - 6), 0);
  649.         ::RGBForeColor(&gAGARamp[r4]);
  650.         ::Move(-1, 0);
  651.         ::Line(-1, -1);
  652.  
  653.         // Add 2nd inner pixels.
  654.         ::MoveTo(r.left + 2, r.bottom - 4);
  655.         ::RGBForeColor(&gAGARamp[rW]);
  656.         ::Line(0, -(r.bottom - r.top - 6));
  657.         ::Line(1, 1);
  658.         ::Line(0, -1);
  659.         ::Line(r.right - r.left - 7, 0);
  660.         ::Move(1, 1);
  661.         ::RGBForeColor(&gAGARamp[r5]);
  662.         ::Line(0, r.bottom - r.top - 7);
  663.         ::Line(-1, 0);
  664.         ::Line(0, 1);
  665.         ::Line(- (r.right - r.left - 7), 0);
  666.         }
  667.     else    // 1-bit
  668.         {
  669.         ::RGBForeColor(&gAGARamp[rW]);
  670.         ::PaintRoundRect(&r, 7, 7);
  671.         ::RGBForeColor(&gAGARamp[rB]);
  672.         ::FrameRoundRect(&r, 7, 7);
  673.         }
  674.  
  675.     // Draw the title.
  676.     AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kNormalOutput, deep, mTextStyle);
  677.     
  678.     // Draw the default button outline.
  679.     this->DrawOutlineNormal(deep);
  680.     }
  681.  
  682. void AGAPushButton::DrawButtonPressed(Boolean deep)
  683.     {
  684.     // Draw the button in enabled/pressed state.
  685.  
  686.     Rect    r = mBounds;
  687.     
  688.     if (mIsDefault && mFrameInside)
  689.         ::InsetRect(&r, 3, 3);
  690.     
  691.     ::PenSize(1, 1);
  692.  
  693.     if (deep)
  694.         {
  695.         // Fill the interior.
  696.         ::InsetRect(&r, 1, 1);
  697.         ::RGBForeColor(&gAGARamp[r9]);
  698.         ::PaintRect(&r);
  699.         ::InsetRect(&r, -1, -1);
  700.         
  701.         // Draw the frame.
  702.         ::MoveTo(r.left + 1, r.top + 1);
  703.         ::RGBForeColor(&gAGARamp[rB]);
  704.         ::Line(0, 0);
  705.         ::Move(1, -1);
  706.         ::RGBForeColor(&gAGARamp[r12]);
  707.         ::Line(0, 0);
  708.         ::Move(1, 0);
  709.         ::RGBForeColor(&gAGARamp[rB]);
  710.         ::Line(r.right - r.left - 6, 0);
  711.         ::RGBForeColor(&gAGARamp[r12]);
  712.         ::Line(0, 0);
  713.         ::Move(1, 1);
  714.         ::RGBForeColor(&gAGARamp[rB]);
  715.         ::Line(0, 0);
  716.         ::Move(1, 1);
  717.         ::RGBForeColor(&gAGARamp[r12]);
  718.         ::Line(0, 0);
  719.         ::Move(0, 1);
  720.         ::RGBForeColor(&gAGARamp[rB]);
  721.         ::Line(0, r.bottom - r.top - 6);
  722.         ::RGBForeColor(&gAGARamp[r12]);
  723.         ::Line(0, 0);
  724.         ::Move(-1, 1);
  725.         ::RGBForeColor(&gAGARamp[rB]);
  726.         ::Line(0, 0);
  727.         ::Move(-1, 1);
  728.         ::RGBForeColor(&gAGARamp[r12]);
  729.         ::Line(0, 0);
  730.         ::Move(-1, 0);
  731.         ::RGBForeColor(&gAGARamp[rB]);
  732.         ::Line(- (r.right - r.left - 6), 0);
  733.         ::RGBForeColor(&gAGARamp[r12]);
  734.         ::Line(0, 0);
  735.         ::Move(-1, -1);
  736.         ::RGBForeColor(&gAGARamp[rB]);
  737.         ::Line(0, 0);
  738.         ::Move(-1, -1);
  739.         ::RGBForeColor(&gAGARamp[r12]);
  740.         ::Line(0, 0);
  741.         ::Move(0, -1);
  742.         ::RGBForeColor(&gAGARamp[rB]);
  743.         ::Line(0, -(r.bottom - r.top - 6));
  744.         ::RGBForeColor(&gAGARamp[r12]);
  745.         ::Line(0, 0);
  746.         
  747.         // Add 1st inner pixels.
  748.         ::MoveTo(r.left + 1, r.bottom - 3);
  749.         ::RGBForeColor(&gAGARamp[r11]);
  750.         ::Line(0, -(r.bottom - r.top - 5));
  751.         ::Line(1, 0);
  752.         ::Line(0, -1);
  753.         ::Line(r.right - r.left - 5, 0);
  754.         ::Move(1, 1);
  755.         ::RGBForeColor(&gAGARamp[r8]);
  756.         ::Line(0, 0);
  757.         ::Move(0, 1);
  758.         ::RGBForeColor(&gAGARamp[r7]);
  759.         ::Line(0, r.bottom - r.top - 6);
  760.         ::Line(-1, 0);
  761.         ::Line(0, 1);
  762.         ::Line(- (r.right - r.left - 5), 0);
  763.         ::RGBForeColor(&gAGARamp[r8]);
  764.         ::Line(0, 0);
  765.  
  766.         // Add 2nd inner pixels.
  767.         ::MoveTo(r.left + 2, r.bottom - 4);
  768.         ::RGBForeColor(&gAGARamp[r10]);
  769.         ::Line(0, -(r.bottom - r.top - 7));
  770.         ::Line(1, 0);
  771.         ::Line(0, -1);
  772.         ::Line(r.right - r.left - 7, 0);
  773.         ::Move(1, 1);
  774.         ::RGBForeColor(&gAGARamp[r8]);
  775.         ::Line(0, r.bottom - r.top - 7);
  776.         ::Line(-1, 0);
  777.         ::Line(0, 1);
  778.         ::Line(- (r.right - r.left - 7), 0);
  779.         }
  780.     else    // 1-bit
  781.         {
  782.         ::RGBForeColor(&gAGARamp[rB]);
  783.         ::PaintRoundRect(&r, 7, 7);
  784.         }
  785.  
  786.     // Draw the title.
  787.     AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kInverseOutput, deep, mTextStyle);
  788.     
  789.     // Draw the default button outline.
  790.     this->DrawOutlineNormal(deep);
  791.     }
  792.  
  793. void AGAPushButton::DrawButtonDisabled(Boolean deep)
  794.     {
  795.     // Draw the button in disabled/unpressed state.
  796.  
  797.     Rect    r = mBounds;
  798.     
  799.     if (mIsDefault && mFrameInside)
  800.         ::InsetRect(&r, 3, 3);
  801.     
  802.     ::PenSize(1, 1);
  803.  
  804.     if (deep)
  805.         {
  806.         // Fill the interior.
  807.         ::InsetRect(&r, 1, 1);
  808.         ::RGBForeColor(&gAGARamp[r2]);
  809.         ::PaintRect(&r);
  810.         ::InsetRect(&r, -1, -1);
  811.         
  812.         // Draw the frame.
  813.         ::MoveTo(r.left + 1, r.top + 1);
  814.         ::RGBForeColor(&gAGARamp[r7]);
  815.         ::Line(0, 0);
  816.         ::Move(1, -1);
  817.         ::Line(0, 0);
  818.         ::Move(1, 0);
  819.         ::Line(r.right - r.left - 6, 0);
  820.         ::Line(0, 0);
  821.         ::Move(1, 1);
  822.         ::Line(0, 0);
  823.         ::Move(1, 1);
  824.         ::Line(0, 0);
  825.         ::Move(0, 1);
  826.         ::Line(0, r.bottom - r.top - 6);
  827.         ::Line(0, 0);
  828.         ::Move(-1, 1);
  829.         ::Line(0, 0);
  830.         ::Move(-1, 1);
  831.         ::Line(0, 0);
  832.         ::Move(-1, 0);
  833.         ::Line(- (r.right - r.left - 6), 0);
  834.         ::Line(0, 0);
  835.         ::Move(-1, -1);
  836.         ::Line(0, 0);
  837.         ::Move(-1, -1);
  838.         ::Line(0, 0);
  839.         ::Move(0, -1);
  840.         ::Line(0, -(r.bottom - r.top - 6));
  841.         ::Line(0, 0);
  842.         
  843.         // Add 1st inner pixels.
  844.         ::MoveTo(r.left + 1, r.top + 2);
  845.         ::RGBForeColor(&gAGARamp[r4]);
  846.         ::Line(0, 0);
  847.         ::Move(1, -1);
  848.         ::Line(0, 0);
  849.         ::Move(r.right - r.left - 5, 0);
  850.         ::Line(0, 0);
  851.         ::Move(1, 1);
  852.         ::Line(0, 0);
  853.         ::Move(0, 1);
  854.         ::RGBForeColor(&gAGARamp[r5]);
  855.         ::Line(0, r.bottom - r.top - 6);
  856.         ::Line(-1, 0);
  857.         ::Line(0, 1);
  858.         ::Line(- (r.right - r.left - 6), 0);
  859.         ::RGBForeColor(&gAGARamp[r4]);
  860.         ::Move(-1, 0);
  861.         ::Line(-1, -1);
  862.  
  863.         // Add 2nd inner pixels.
  864.         ::MoveTo(r.left + 2, r.bottom - 4);
  865.         ::RGBForeColor(&gAGARamp[r1]);
  866.         ::Line(0, -(r.bottom - r.top - 6));
  867.         ::Line(1, 1);
  868.         ::Line(0, -1);
  869.         ::Line(r.right - r.left - 7, 0);
  870.         ::Move(1, 1);
  871.         ::RGBForeColor(&gAGARamp[r4]);
  872.         ::Line(0, r.bottom - r.top - 7);
  873.         ::Line(-1, 0);
  874.         ::Line(0, 1);
  875.         ::Line(- (r.right - r.left - 7), 0);
  876.         }
  877.     else    // 1-bit
  878.         {
  879.         ::RGBForeColor(&gAGARamp[rW]);
  880.         ::PaintRoundRect(&r, 7, 7);
  881.         ::RGBForeColor(&gAGARamp[rB]);
  882.         ::FrameRoundRect(&r, 7, 7);
  883.         }
  884.  
  885.     // Draw the title.
  886.     AGAStringOut(mTitle, &r, truncMiddle, teJustCenter, kDisabledOutput, deep, mTextStyle);
  887.     
  888.     // Draw the default button outline.
  889.     this->DrawOutlineDisabled(deep);
  890.     
  891.     if (! deep)
  892.         {
  893.         if (mIsDefault)
  894.             ::InsetRect(&r, -3, -3);
  895.  
  896.         ::RGBForeColor(&gAGARamp[rB]);
  897.         ::PenPat(&qd.gray);
  898.         ::PenMode(patBic);
  899.         ::PaintRect(&r);
  900.  
  901.         ::PenNormal();
  902.         }
  903.     }
  904.  
  905. void AGAPushButton::DrawOutlineNormal(Boolean deep)
  906.     {
  907.     // Draw the default button outline in normal
  908.     // state if the button has one. It may be either
  909.     // inside or outside mBounds.
  910.     
  911.     // If we are drawing the outline outside the normal
  912.     // bounds, we should force the clipping to include
  913.     // that outside area, because the framework or whoever
  914.     // may have reduced clipping to our bounds.
  915.  
  916.     if (! mIsDefault)
  917.         return;
  918.  
  919.     Rect    r = mBounds;
  920.     
  921.     if (! mFrameInside)
  922.         ::InsetRect(&r, -3, -3);
  923.  
  924.     if (deep)
  925.         {
  926.         // Draw the frame.
  927.         ::MoveTo(r.left + 1, r.top + 2);
  928.         ::RGBForeColor(&gAGARamp[rB]);
  929.         ::Line(1, -1);
  930.         ::Move(1, -1);
  931.         ::RGBForeColor(&gAGARamp[r12]);
  932.         ::Line(0, 0);
  933.         ::Move(1, 0);
  934.         ::RGBForeColor(&gAGARamp[rB]);
  935.         ::Line(r.right - r.left - 8, 0);
  936.         ::RGBForeColor(&gAGARamp[r12]);
  937.         ::Line(0, 0);
  938.         ::Move(1, 1);
  939.         ::RGBForeColor(&gAGARamp[rB]);
  940.         ::Line(1, 1);
  941.         ::Move(1, 1);
  942.         ::RGBForeColor(&gAGARamp[r12]);
  943.         ::Line(0, 0);
  944.         ::Move(0, 1);
  945.         ::RGBForeColor(&gAGARamp[rB]);
  946.         ::Line(0, r.bottom - r.top - 8);
  947.         ::RGBForeColor(&gAGARamp[r12]);
  948.         ::Line(0, 0);
  949.         ::Move(-1, 1);
  950.         ::RGBForeColor(&gAGARamp[rB]);
  951.         ::Line(-1, 1);
  952.         ::Move(-1, 1);
  953.         ::RGBForeColor(&gAGARamp[r12]);
  954.         ::Line(0, 0);
  955.         ::Move(-1, 0);
  956.         ::RGBForeColor(&gAGARamp[rB]);
  957.         ::Line(- (r.right - r.left - 8), 0);
  958.         ::RGBForeColor(&gAGARamp[r12]);
  959.         ::Line(0, 0);
  960.         ::Move(-1, -1);
  961.         ::RGBForeColor(&gAGARamp[rB]);
  962.         ::Line(-1, -1);
  963.         ::Move(-1, -1);
  964.         ::RGBForeColor(&gAGARamp[r12]);
  965.         ::Line(0, 0);
  966.         ::Move(0, -1);
  967.         ::RGBForeColor(&gAGARamp[rB]);
  968.         ::Line(0, -(r.bottom - r.top - 8));
  969.         ::RGBForeColor(&gAGARamp[r12]);
  970.         ::Line(0, 0);
  971.         
  972.         // Draw the interior.
  973.         ::MoveTo(r.left + 1, r.bottom - 4);
  974.         ::RGBForeColor(&gAGARamp[r2]);
  975.         ::Line(0, -(r.bottom - r.top - 7));
  976.         ::Line(1, 0);
  977.         ::Line(0, -1);
  978.         ::Line(1, 0);
  979.         ::Line(0, -1);
  980.         ::Line(r.right - r.left - 8, 0);
  981.         ::Move(1, 0);
  982.         ::RGBForeColor(&gAGARamp[r3]);
  983.         ::Line(0, 0);
  984.         ::Move(1, 1);
  985.         ::RGBForeColor(&gAGARamp[r4]);
  986.         ::Line(0, 0);
  987.         ::Move(1, 1);
  988.         ::RGBForeColor(&gAGARamp[r7]);
  989.         ::Line(0, 1);
  990.         ::RGBForeColor(&gAGARamp[r8]);
  991.         ::Line(0, r.bottom - r.top - 8);
  992.         ::Line(-2, 2);
  993.         ::Line(-(r.right - r.left - 8), 0);
  994.         ::Move(-1, 0);
  995.         ::RGBForeColor(&gAGARamp[r7]);
  996.         ::Line(0, 0);
  997.         ::Move(-1, -1);
  998.         ::RGBForeColor(&gAGARamp[r4]);
  999.         ::Line(0, 0);
  1000.         ::Move(-1, -1);
  1001.         ::RGBForeColor(&gAGARamp[r3]);
  1002.         ::Line(0, 0);
  1003.         ::Move(1, 0);
  1004.         ::RGBForeColor(&gAGARamp[r5]);
  1005.         ::Line(0, -(r.bottom - r.top - 8));
  1006.         ::Line(2, -2);
  1007.         ::Line(r.right - r.left - 8, 0);
  1008.         ::Line(0, 1);
  1009.         ::Line(1, 0);
  1010.         ::Line(0, r.bottom - r.top - 8);
  1011.         ::Line(-2, 2);
  1012.         ::Line(-(r.right - r.left - 8), 0);
  1013.         ::Line(0, -1);
  1014.         ::Move(0, -1);
  1015.         ::RGBForeColor(&gAGARamp[r8]);
  1016.         ::Line(1, 1);
  1017.         ::MoveTo(r.left + 3, r.top + 4);
  1018.         ::Line(1, -1);
  1019.         ::MoveTo(r.right -5, r.top + 3);
  1020.         ::Line(1, 1);
  1021.         ::MoveTo(r.right -5, r.bottom - 4);
  1022.         ::Line(1, -1);
  1023.         ::Move(1, 1);
  1024.         ::RGBForeColor(&gAGARamp[r7]);
  1025.         ::Line(-1, 1);
  1026.         }
  1027.     else
  1028.         {
  1029.         ::RGBForeColor(&gAGARamp[rB]);
  1030.         ::PenSize(2, 2);
  1031.         ::FrameRoundRect(&r, 11, 11);
  1032.         ::PenSize(1, 1);
  1033.         }
  1034.     }
  1035.  
  1036. void AGAPushButton::DrawOutlineDisabled(Boolean deep)
  1037.     {
  1038.     // Draw the default button outline in disabled
  1039.     // state if the button has one. It may be either
  1040.     // inside or outside mBounds.
  1041.  
  1042.     if (! mIsDefault)
  1043.         return;
  1044.  
  1045.     Rect    r = mBounds;
  1046.     
  1047.     if (! mFrameInside)
  1048.         ::InsetRect(&r, -3, -3);
  1049.  
  1050.     if (deep)
  1051.         {
  1052.         // Draw the frame.
  1053.         ::MoveTo(r.left + 1, r.top + 2);
  1054.         ::RGBForeColor(&gAGARamp[r7]);
  1055.         ::Line(1, -1);
  1056.         ::Move(1, -1);
  1057.         ::Line(0, 0);
  1058.         ::Move(1, 0);
  1059.         ::Line(r.right - r.left - 8, 0);
  1060.         ::Line(0, 0);
  1061.         ::Move(1, 1);
  1062.         ::Line(1, 1);
  1063.         ::Move(1, 1);
  1064.         ::Line(0, 0);
  1065.         ::Move(0, 1);
  1066.         ::Line(0, r.bottom - r.top - 8);
  1067.         ::Line(0, 0);
  1068.         ::Move(-1, 1);
  1069.         ::Line(-1, 1);
  1070.         ::Move(-1, 1);
  1071.         ::Line(0, 0);
  1072.         ::Move(-1, 0);
  1073.         ::Line(- (r.right - r.left - 8), 0);
  1074.         ::Line(0, 0);
  1075.         ::Move(-1, -1);
  1076.         ::Line(-1, -1);
  1077.         ::Move(-1, -1);
  1078.         ::Line(0, 0);
  1079.         ::Move(0, -1);
  1080.         ::Line(0, -(r.bottom - r.top - 8));
  1081.         ::Line(0, 0);
  1082.         
  1083.         // Draw the interior.
  1084.         ::MoveTo(r.left + 1, r.bottom - 4);
  1085.         ::RGBForeColor(&gAGARamp[r1]);
  1086.         ::Line(0, -(r.bottom - r.top - 7));
  1087.         ::Line(1, 0);
  1088.         ::Line(0, -1);
  1089.         ::Line(1, 0);
  1090.         ::Line(0, -1);
  1091.         ::Line(r.right - r.left - 8, 0);
  1092.         ::Move(3, 2);
  1093.         ::RGBForeColor(&gAGARamp[r6]);
  1094.         ::Line(0, r.bottom - r.top - 7);
  1095.         ::Line(-1, 0);
  1096.         ::Line(0, 1);
  1097.         ::Line(-1, 0);
  1098.         ::Line(0, 1);
  1099.         ::Line(-(r.right - r.left - 7), 0);
  1100.         ::Move(-2, -2);
  1101.         ::RGBForeColor(&gAGARamp[r4]);
  1102.         ::Line(1, 1);
  1103.         ::Line(0, -(r.bottom - r.top - 7));
  1104.         ::Line(1, 0);
  1105.         ::Line(0, -1);
  1106.         ::Line(1, 0);
  1107.         ::Line(0, -1);
  1108.         ::Line(r.right - r.left - 7, 0);
  1109.         ::Line(-1, -1);
  1110.         ::Move(-1, 2);
  1111.         ::Line(2, 0);
  1112.         ::Move(-1, 1);
  1113.         ::Line(1, 0);
  1114.         ::Line(0, r.bottom - r.top - 9);
  1115.         ::Line(-1, 0);
  1116.         ::Line(0, 1);
  1117.         ::Line(-1, 0);
  1118.         ::Line(0, 1);
  1119.         ::Line(-(r.right - r.left - 8), 0);
  1120.         ::Line(0, -2);
  1121.         ::Line(1, 1);
  1122.         }
  1123.     else
  1124.         {
  1125.         ::RGBForeColor(&gAGARamp[rB]);
  1126.         ::PenSize(2, 2);
  1127.         ::FrameRoundRect(&r, 11, 11);
  1128.         ::PenSize(1, 1);
  1129.         }
  1130.     }
  1131.  
  1132. //
  1133. // AGACheckBox ---------------------------------------------------------------
  1134. //
  1135. // This class implements a standard checkbox object with the additional
  1136. // capability of supporting mixed state.
  1137. //
  1138.  
  1139. AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, Boolean automaticState)
  1140. : AGAObject(bounds)
  1141.     {
  1142.     // Construct with initial empty button title.
  1143.  
  1144.     mValue = kCheckBoxOff;
  1145.     mAutomaticState = automaticState;
  1146.     mTitle[0];
  1147.     mTextStyle = textStyle;
  1148.     }
  1149.  
  1150. AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, StringPtr title, Boolean automaticState)
  1151. : AGAObject(bounds)
  1152.     {
  1153.     // Construct with specified button title.
  1154.  
  1155.     mValue = kCheckBoxOff;
  1156.     mAutomaticState = automaticState;
  1157.     PLstrcpy(mTitle, title);
  1158.     mTextStyle = textStyle;
  1159.     }
  1160.  
  1161. AGACheckBox::AGACheckBox(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex, Boolean automaticState)
  1162. : AGAObject(bounds)
  1163.     {
  1164.     // Construct by getting button title from specified resource.
  1165.  
  1166.     mValue = kCheckBoxOff;
  1167.     mAutomaticState = automaticState;
  1168.     ::GetIndString(mTitle, stringListResourceID, stringIndex);
  1169.     mTextStyle = textStyle;
  1170.     }
  1171.  
  1172. AGACheckBox::~AGACheckBox()
  1173.     {
  1174.     }
  1175.  
  1176. void AGACheckBox::DrawObject()
  1177.     {
  1178.     // Draw button in normal unpressed state.
  1179.  
  1180.     this->DrawButton(kNotPressed);
  1181.     }
  1182.  
  1183. Boolean AGACheckBox::TrackMouse(Point mouseLocation)
  1184.     {
  1185.     // If inherited tracking succeeded and we are set to
  1186.     // automatically change our state, toggle it.
  1187.  
  1188.     Boolean    wasItHit = AGAObject::TrackMouse(mouseLocation);
  1189.  
  1190.     if (wasItHit && mAutomaticState)
  1191.         this->SetValue((mValue == kCheckBoxOn) ? kCheckBoxOff : kCheckBoxOn, kRedraw);
  1192.  
  1193.     return wasItHit;
  1194.     }
  1195.  
  1196. void AGACheckBox::SetTitle(StringPtr title, Boolean redraw)
  1197.     {
  1198.     // Change button title, redraw if specified.
  1199.  
  1200.     PLstrcpy(mTitle, title);
  1201.     
  1202.     if (redraw)
  1203.         this->DrawObject();
  1204.     }
  1205.  
  1206. SInt32 AGACheckBox::GetValue()
  1207.     {
  1208.     // Return current state.
  1209.  
  1210.     return mValue;
  1211.     }
  1212.  
  1213. void AGACheckBox::SetValue(SInt32 newValue, Boolean redraw)
  1214.     {
  1215.     // Set current state, redraw if specified and necessary.
  1216.  
  1217.     if (newValue != mValue)
  1218.         {
  1219.         mValue = newValue;
  1220.         
  1221.         if (redraw)
  1222.             {
  1223.             this->DrawButton(kNotPressed);
  1224.             }
  1225.         }
  1226.     }
  1227.  
  1228. void AGACheckBox::DrawButton(Boolean pressed)
  1229.     {
  1230.     CleansePen();
  1231.  
  1232.     // Draw the button in the appropriate state.
  1233.  
  1234.     GDIterator    iter;
  1235.     Boolean        deep;
  1236.  
  1237.     while (iter.More(deep))
  1238.         {
  1239.         if (! mEnabled)
  1240.             this->DrawButtonDisabled(deep);
  1241.         else if (pressed)
  1242.             this->DrawButtonPressed(deep);
  1243.         else
  1244.             this->DrawButtonNormal(deep);
  1245.         }
  1246.  
  1247.     CleansePen();
  1248.     }
  1249.  
  1250. void AGACheckBox::SetTrackingState(Boolean isIn)
  1251.     {
  1252.     // Draw the button pressed or unpressed as specified.
  1253.  
  1254.     this->DrawButton(isIn);
  1255.     }
  1256.  
  1257. void AGACheckBox::DrawButtonNormal(Boolean deep)
  1258.     {
  1259.     // Draw the button in enabled/unpressed state.
  1260.  
  1261.     Rect    r = mBounds;
  1262.     
  1263.     r.bottom = r.top + kCheckBoxSize;
  1264.     r.right = r.left + kCheckBoxSize;
  1265.     
  1266.     ::PenSize(1, 1);
  1267.  
  1268.     if (deep)
  1269.         {
  1270.         // Fill the interior.
  1271.         ::InsetRect(&r, 1, 1);
  1272.         ::RGBForeColor(&gAGARamp[r2]);
  1273.         ::PaintRect(&r);
  1274.         ::InsetRect(&r, -1, -1);
  1275.         
  1276.         // Draw the frame.
  1277.         ::RGBForeColor(&gAGARamp[rB]);
  1278.         ::FrameRect(&r);
  1279.         
  1280.         // Draw the edges.
  1281.         ::MoveTo(r.left + 1, r.bottom - 3);
  1282.         ::RGBForeColor(&gAGARamp[rW]);
  1283.         ::Line(0, -8);
  1284.         ::Line(8, 0);
  1285.         ::Move(1, 1);
  1286.         ::RGBForeColor(&gAGARamp[r7]);
  1287.         ::Line(0, 8);
  1288.         ::Line(-8, 0);
  1289.         
  1290.         if (mValue == kCheckBoxOn)
  1291.             {
  1292.             // Draw the X and its shadow.
  1293.             ::MoveTo(r.left + 3, r.top + 2);
  1294.             ::RGBForeColor(&gAGARamp[rB]);
  1295.             ::Line(5, 5);
  1296.             ::Move(0, 1);
  1297.             ::Line(-5, -5);
  1298.             ::Move(0, 4);
  1299.             ::Line(5, -5);
  1300.             ::Move(0, 1);
  1301.             ::Line(-5, 5);
  1302.             ::Move(1, 0);
  1303.             ::RGBForeColor(&gAGARamp[r8]);
  1304.             ::Line(1, -1);
  1305.             ::Move(2, -2);
  1306.             ::Line(2, -2);
  1307.             ::Move(0, 1);
  1308.             ::RGBForeColor(&gAGARamp[r5]);
  1309.             ::Line(-1, 1);
  1310.             ::Move(-2, 2);
  1311.             ::Line(-2, 2);
  1312.             ::Move(5, 0);
  1313.             ::Line(0, 0);
  1314.             ::Move(0, -1);
  1315.             ::RGBForeColor(&gAGARamp[r8]);
  1316.             ::Line(0, 0);
  1317.             }
  1318.         else if (mValue == kCheckBoxMixed)
  1319.             {
  1320.             // Draw the dash and its shadow.
  1321.             ::MoveTo(r.left + 3, r.top + 5);
  1322.             ::PenSize(2, 2);
  1323.             ::RGBForeColor(&gAGARamp[rB]);
  1324.             ::Line(4, 0);
  1325.             
  1326.             ::MoveTo(r.left + 4, r.top + 7);
  1327.             ::PenSize(1, 1);
  1328.             ::RGBForeColor(&gAGARamp[r5]);
  1329.             ::Line(5, 0);
  1330.             ::Line(-2, 0);
  1331.             }
  1332.         }
  1333.     else
  1334.         {
  1335.         // Paint white over previous junk, if any.
  1336.         ::RGBForeColor(&gAGARamp[rW]);
  1337.         ::PaintRect(&r);
  1338.         // Paint frame.
  1339.         ::RGBForeColor(&gAGARamp[rB]);
  1340.         ::FrameRect(&r);
  1341.  
  1342.         // Draw check or dash.
  1343.         if (mValue == kCheckBoxOn)
  1344.             {
  1345.             ::PenSize(1, 1);
  1346.             ::MoveTo(r.left, r.top);
  1347.             ::Line(kCheckBoxSize-1, kCheckBoxSize-1);
  1348.             ::Move(-(kCheckBoxSize-1), 0);
  1349.             ::Line(kCheckBoxSize-1, -(kCheckBoxSize-1));
  1350.             }
  1351.         else if (mValue == kCheckBoxMixed)
  1352.             {
  1353.             ::PenSize(1, 2);
  1354.             ::MoveTo(r.left + 3, r.top + 5);
  1355.             ::Line(5, 0);
  1356.             }
  1357.         
  1358.         ::PenNormal();
  1359.         }
  1360.  
  1361.     // Draw the title.
  1362.     r = mBounds;
  1363.     r.left += (kCheckBoxSize + 6);
  1364.     r.bottom = r.top + kCheckBoxSize;
  1365.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
  1366.     }
  1367.  
  1368. void AGACheckBox::DrawButtonPressed(Boolean deep)
  1369.     {
  1370.     // Draw the button in enabled/pressed state.
  1371.  
  1372.     Rect    r = mBounds;
  1373.     
  1374.     r.bottom = r.top + kCheckBoxSize;
  1375.     r.right = r.left + kCheckBoxSize;
  1376.     
  1377.     ::PenSize(1, 1);
  1378.  
  1379.     if (deep)
  1380.         {
  1381.         // Fill the interior.
  1382.         ::InsetRect(&r, 1, 1);
  1383.         ::RGBForeColor(&gAGARamp[r8]);
  1384.         ::PaintRect(&r);
  1385.         ::InsetRect(&r, -1, -1);
  1386.         
  1387.         // Draw the frame.
  1388.         ::RGBForeColor(&gAGARamp[rB]);
  1389.         ::FrameRect(&r);
  1390.         
  1391.         // Draw the edges.
  1392.         ::MoveTo(r.left + 1, r.bottom - 3);
  1393.         ::RGBForeColor(&gAGARamp[r10]);
  1394.         ::Line(0, -8);
  1395.         ::Line(8, 0);
  1396.         ::Move(1, 1);
  1397.         ::RGBForeColor(&gAGARamp[r6]);
  1398.         ::Line(0, 8);
  1399.         ::Line(-8, 0);
  1400.         
  1401.         if (mValue == kCheckBoxOn)
  1402.             {
  1403.             // Draw the X and its shadow.
  1404.             ::MoveTo(r.left + 3, r.top + 2);
  1405.             ::RGBForeColor(&gAGARamp[rB]);
  1406.             ::Line(5, 5);
  1407.             ::Move(0, 1);
  1408.             ::Line(-5, -5);
  1409.             ::Move(0, 4);
  1410.             ::Line(5, -5);
  1411.             ::Move(0, 1);
  1412.             ::Line(-5, 5);
  1413.             ::Move(1, 0);
  1414.             ::RGBForeColor(&gAGARamp[r11]);
  1415.             ::Line(1, -1);
  1416.             ::Move(2, -2);
  1417.             ::Line(2, -2);
  1418.             ::Move(0, 1);
  1419.             ::RGBForeColor(&gAGARamp[r10]);
  1420.             ::Line(-1, 1);
  1421.             ::Move(-2, 2);
  1422.             ::Line(-2, 2);
  1423.             ::Move(5, 0);
  1424.             ::Line(0, 0);
  1425.             ::Move(0, -1);
  1426.             ::RGBForeColor(&gAGARamp[r11]);
  1427.             ::Line(0, 0);
  1428.             }
  1429.         else if (mValue == kCheckBoxMixed)
  1430.             {
  1431.             // Draw the dash and its shadow.
  1432.             ::MoveTo(r.left + 3, r.top + 5);
  1433.             ::PenSize(2, 2);
  1434.             ::RGBForeColor(&gAGARamp[rB]);
  1435.             ::Line(4, 0);
  1436.             
  1437.             ::MoveTo(r.left + 4, r.top + 7);
  1438.             ::PenSize(1, 1);
  1439.             ::RGBForeColor(&gAGARamp[r10]);
  1440.             ::Line(5, 0);
  1441.             ::Line(-2, 0);
  1442.             }
  1443.         }
  1444.     else
  1445.         {
  1446.         // Paint white over previous junk, if any.
  1447.         ::RGBForeColor(&gAGARamp[rW]);
  1448.         ::PaintRect(&r);
  1449.         // Paint frame.
  1450.         ::RGBForeColor(&gAGARamp[rB]);
  1451.         ::PenSize(2, 2);
  1452.         ::FrameRect(&r);
  1453.  
  1454.         // Draw check or dash.
  1455.         if (mValue == kCheckBoxOn)
  1456.             {
  1457.             ::PenSize(1, 1);
  1458.             ::MoveTo(r.left, r.top);
  1459.             ::Line(kCheckBoxSize-1, kCheckBoxSize-1);
  1460.             ::Move(-(kCheckBoxSize-1), 0);
  1461.             ::Line(kCheckBoxSize-1, -(kCheckBoxSize-1));
  1462.             }
  1463.         else if (mValue == kCheckBoxMixed)
  1464.             {
  1465.             ::PenSize(1, 2);
  1466.             ::MoveTo(r.left + 3, r.top + 5);
  1467.             ::Line(5, 0);
  1468.             }
  1469.         
  1470.         ::PenNormal();
  1471.         }
  1472.  
  1473.     // Draw the title.
  1474.     r = mBounds;
  1475.     r.left += (kCheckBoxSize + 6);
  1476.     r.bottom = r.top + kCheckBoxSize;
  1477.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
  1478.     }
  1479.  
  1480. void AGACheckBox::DrawButtonDisabled(Boolean deep)
  1481.     {
  1482.     // Draw the button in disabled/unpressed state.
  1483.  
  1484.     Rect    r = mBounds;
  1485.     
  1486.     r.bottom = r.top + kCheckBoxSize;
  1487.     r.right = r.left + kCheckBoxSize;
  1488.     
  1489.     ::PenSize(1, 1);
  1490.  
  1491.     if (deep)
  1492.         {
  1493.         // Fill the interior.
  1494.         ::InsetRect(&r, 1, 1);
  1495.         ::RGBForeColor(&gAGARamp[r2]);
  1496.         ::PaintRect(&r);
  1497.         ::InsetRect(&r, -1, -1);
  1498.         
  1499.         // Draw the frame.
  1500.         ::RGBForeColor(&gAGARamp[r7]);
  1501.         ::FrameRect(&r);
  1502.         
  1503.         // Draw the edges.
  1504.         ::MoveTo(r.left + 1, r.bottom - 3);
  1505.         ::RGBForeColor(&gAGARamp[rW]);
  1506.         ::Line(0, -8);
  1507.         ::Line(8, 0);
  1508.         ::Move(1, 1);
  1509.         ::RGBForeColor(&gAGARamp[r5]);
  1510.         ::Line(0, 8);
  1511.         ::Line(-8, 0);
  1512.         
  1513.         if (mValue == kCheckBoxOn)
  1514.             {
  1515.             // Draw the X and its shadow.
  1516.             ::MoveTo(r.left + 3, r.top + 2);
  1517.             ::RGBForeColor(&gAGARamp[r7]);
  1518.             ::Line(5, 5);
  1519.             ::Move(0, 1);
  1520.             ::Line(-5, -5);
  1521.             ::Move(0, 4);
  1522.             ::Line(5, -5);
  1523.             ::Move(0, 1);
  1524.             ::Line(-5, 5);
  1525.             ::Move(1, 0);
  1526.             ::RGBForeColor(&gAGARamp[r5]);
  1527.             ::Line(1, -1);
  1528.             ::Move(2, -2);
  1529.             ::Line(2, -2);
  1530.             ::Move(0, 1);
  1531.             ::Line(-1, 1);
  1532.             ::Move(-2, 2);
  1533.             ::Line(-2, 2);
  1534.             ::Move(5, 0);
  1535.             ::Line(0, 0);
  1536.             ::Move(0, -1);
  1537.             ::Line(0, 0);
  1538.             }
  1539.         else if (mValue == kCheckBoxMixed)
  1540.             {
  1541.             // Draw the dash and its shadow.
  1542.             ::MoveTo(r.left + 3, r.top + 5);
  1543.             ::PenSize(2, 2);
  1544.             ::RGBForeColor(&gAGARamp[r7]);
  1545.             ::Line(4, 0);
  1546.             
  1547.             ::MoveTo(r.left + 4, r.top + 7);
  1548.             ::PenSize(1, 1);
  1549.             ::RGBForeColor(&gAGARamp[r5]);
  1550.             ::Line(5, 0);
  1551.             ::Line(-2, 0);
  1552.             }
  1553.         }
  1554.     else
  1555.         {
  1556.         // Paint white over previous junk, if any.
  1557.         ::RGBForeColor(&gAGARamp[rW]);
  1558.         ::PaintRect(&r);
  1559.  
  1560.         // Paint frame.
  1561.         ::PenPat(&qd.gray);
  1562.         ::RGBForeColor(&gAGARamp[rB]);
  1563.         ::FrameRect(&r);
  1564.  
  1565.         // Draw check or dash.
  1566.         if (mValue == kCheckBoxOn)
  1567.             {
  1568.             ::PenPat(&qd.black);    // 1-pixel diagonals can disappear when qd.gray
  1569.             ::MoveTo(r.left + 2, r.top + 2);
  1570.             ::Line(kCheckBoxSize-5, kCheckBoxSize-5);
  1571.             ::Move(-(kCheckBoxSize-5), 0);
  1572.             ::Line(kCheckBoxSize-5, -(kCheckBoxSize-5));
  1573.             }
  1574.         else if (mValue == kCheckBoxMixed)
  1575.             {
  1576.             ::PenSize(1, 2);
  1577.             ::MoveTo(r.left + 3, r.top + 5);
  1578.             ::Line(5, 0);
  1579.             }
  1580.         
  1581.         ::PenNormal();
  1582.         }
  1583.  
  1584.     // Draw the title.
  1585.     r = mBounds;
  1586.     r.left += (kCheckBoxSize + 6);
  1587.     r.bottom = r.top + kCheckBoxSize;
  1588.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kDisabledOutput, deep, mTextStyle);
  1589.     }
  1590.  
  1591. //
  1592. // AGAGroupsContainer --------------------------------------------------------
  1593. //
  1594. // This class is used internally to maintain the MExclusiveObject
  1595. // behavior that allows radio buttons to automatically maintain
  1596. // standard radio button group XOR behavior.
  1597. //
  1598.  
  1599. void AGAGroupsContainer::AGAAddGroupMember(MExclusiveObject* groupMember)
  1600.     {
  1601.     // If the supplied object has an ID pair, add it to its
  1602.     // group. Create the group if this is the first member.
  1603.  
  1604.     if ((groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
  1605.         {
  1606.         AGAGroup*    existingGroup = this->FindGroup(groupMember);
  1607.         
  1608.         if (existingGroup == NULL)
  1609.             {
  1610.             AGAGroup    newGroup;
  1611.             
  1612.             newGroup.mGroupIDPart1 = groupMember->mGroupIDPart1;
  1613.             newGroup.mGroupIDPart2 = groupMember->mGroupIDPart2;
  1614.             newGroup.mGroupMembers.push_back(groupMember);
  1615.             
  1616.             mGroups.push_back(newGroup);
  1617.             }
  1618.         else
  1619.             {
  1620.             existingGroup->mGroupMembers.push_back(groupMember);
  1621.             }
  1622.         }
  1623.     }
  1624.  
  1625. void AGAGroupsContainer::AGARemoveGroupMember(MExclusiveObject* groupMember)
  1626.     {
  1627.     // If the supplied object has an ID pair, remove it from its
  1628.     // group. Destroy the group if no more members are left in it.
  1629.  
  1630.     if ((groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
  1631.         {
  1632.         AGAGroup*    existingGroup = this->FindGroup(groupMember);
  1633.         
  1634.         if (existingGroup != NULL)
  1635.             {
  1636.             MExclusiveObject**    memberPtr = this->FindMemberPtr(existingGroup, groupMember);
  1637.             
  1638.             if (memberPtr != NULL)
  1639.                 existingGroup->mGroupMembers.erase(memberPtr);
  1640.             }
  1641.         }
  1642.     }
  1643.  
  1644. void AGAGroupsContainer::AGAHitGroupMember(MExclusiveObject* groupMember)
  1645.     {
  1646.     // If the supplied object has an ID pair, send every other
  1647.     // member of its group the TurnOff message.
  1648.  
  1649.     if ((groupMember->mGroupIDPart1 != kNoGroupID) && (groupMember->mGroupIDPart2 != kNoGroupID))
  1650.         {
  1651.         AGAGroup*    existingGroup = this->FindGroup(groupMember);
  1652.  
  1653.         if (existingGroup != NULL)
  1654.             {
  1655.             for (vector<MExclusiveObject*>::iterator p = existingGroup->mGroupMembers.begin();
  1656.                 p != existingGroup->mGroupMembers.end();
  1657.                 p++)
  1658.                 {
  1659.                 if (*p != groupMember)
  1660.                     (*p)->TurnOff();
  1661.                 }
  1662.             }
  1663.         }
  1664.     }
  1665.  
  1666. AGAGroup* AGAGroupsContainer::FindGroup(MExclusiveObject* groupMember)
  1667.     {
  1668.     // Return a pointer to the group that matches the supplied
  1669.     // object's ID pair. Return NULL if no such group exists.
  1670.  
  1671.     for (vector<AGAGroup>::iterator p = mGroups.begin();
  1672.         p != mGroups.end();
  1673.         p++)
  1674.         {
  1675.         if ((p->mGroupIDPart1 == groupMember->mGroupIDPart1) &&
  1676.             (p->mGroupIDPart2 == groupMember->mGroupIDPart2))
  1677.             return p;
  1678.         }
  1679.  
  1680.     return NULL;
  1681.     }
  1682.  
  1683. MExclusiveObject** AGAGroupsContainer::FindMemberPtr(AGAGroup* itsGroup, MExclusiveObject* groupMember)
  1684.     {
  1685.     // Return a pointer to the vector item for the specified member.
  1686.     // This allows the vector item to operated on (e.g., deleted).
  1687.  
  1688.     for (vector<MExclusiveObject*>::iterator p = itsGroup->mGroupMembers.begin();
  1689.         p != itsGroup->mGroupMembers.end();
  1690.         p++)
  1691.         {
  1692.         if (*p == groupMember)
  1693.             return p;
  1694.         }
  1695.  
  1696.     return NULL;
  1697.     }
  1698.  
  1699. //
  1700. // MExclusiveObject ---------------------------------------------------------------
  1701. //
  1702. // This class is a mixin class for objects that can be included in a
  1703. // group of mutually exclusively selected objects, i.e. radio buttons
  1704. // or icon buttons. When any group member is selected, the others in
  1705. // the group are sent the TurnOff message.
  1706. //
  1707.  
  1708. MExclusiveObject::MExclusiveObject(UInt32 groupIDPart1, UInt32 groupIDPart2)
  1709.     {
  1710.     // Construct by setting the ID pair and adding to
  1711.     // the group.
  1712.  
  1713.     mGroupIDPart1 = groupIDPart1;
  1714.     mGroupIDPart2 = groupIDPart2;
  1715.  
  1716.     gGroupsContainer->AGAAddGroupMember(this);
  1717.     }
  1718.  
  1719. MExclusiveObject::~MExclusiveObject()
  1720.     {
  1721.     // Destruct by removing from the group.
  1722.  
  1723.     gGroupsContainer->AGARemoveGroupMember(this);
  1724.     }
  1725.  
  1726. void MExclusiveObject::TurnOff()
  1727.     {
  1728.     // Override as needed.
  1729.     }
  1730.  
  1731. //
  1732. // AGAOffscreenImage ------------------------------------------------------------
  1733. //
  1734. // AGAOffscreenImage holds the data needed to blast a clipped region
  1735. // of pixel values onto the current port. This is used by the AGARadioButton
  1736. // class to avoid the ultra-tedious pixel-by-pixel drawing of the grayscale
  1737. // radio button images.
  1738. //
  1739.  
  1740. AGAOffscreenImage::AGAOffscreenImage()
  1741.     {
  1742.     mImagePixMap = NULL;
  1743.     mClippingRegion = NULL;
  1744.     }
  1745.  
  1746. AGAOffscreenImage::~AGAOffscreenImage()
  1747.     {
  1748.     if (mImagePixMap != NULL)
  1749.         ::DisposePixMap(mImagePixMap);
  1750.  
  1751.     if (mClippingRegion != NULL)
  1752.         ::DisposeRgn(mClippingRegion);
  1753.     }
  1754.  
  1755. OSErr AGAOffscreenImage::CreateImageData(Point imageSize,
  1756.                                         SInt8* imageColorIndexes,
  1757.                                         RgnHandle clippingRegion)
  1758.     {
  1759.     // Allocate an offscreen PixMap to contain the RGB values
  1760.     // specified.
  1761.  
  1762.     const UInt32 kImageDepth = 4;
  1763.     
  1764.     ::SetRect(&mImageSourceRect, 0, 0, imageSize.h, imageSize.v);
  1765.  
  1766.     if (clippingRegion != NULL)
  1767.         {
  1768.         // Copy the supplied clipping region.
  1769.  
  1770.         mClippingRegion = ::NewRgn();
  1771.         if (mClippingRegion == NULL)
  1772.             return memFullErr;
  1773.  
  1774.         ::CopyRgn(clippingRegion, mClippingRegion);
  1775.         OSErr    result = ::MemError();
  1776.         if (result != noErr)
  1777.             return result;
  1778.         }
  1779.  
  1780.     //
  1781.     // Allocate and set up the PixMap structure.
  1782.     //
  1783.  
  1784.     Ptr    imagePtr = ::NewPtr(kImageDepth * imageSize.h * imageSize.v);
  1785.  
  1786.     if (imagePtr == NULL)
  1787.         return memFullErr;
  1788.  
  1789.     mImagePixMap = ::NewPixMap();
  1790.     ::HLockHi((Handle) mImagePixMap);
  1791.     
  1792.     PixMapPtr    pixMapPtr = *mImagePixMap;
  1793.     
  1794.     pixMapPtr->baseAddr = imagePtr;
  1795.     pixMapPtr->rowBytes = (kImageDepth * imageSize.h) | 0x8000;
  1796.     pixMapPtr->bounds = mImageSourceRect;
  1797.     pixMapPtr->pixelType = RGBDirect;
  1798.     pixMapPtr->pixelSize = 32;    // direct 32-bit color values
  1799.     pixMapPtr->cmpCount = 3;    // 3 color components (RGB)
  1800.     pixMapPtr->cmpSize = 8;        // 8 bits per component
  1801.     pixMapPtr->planeBytes = 0;
  1802.  
  1803.     if (pixMapPtr->pmTable != NULL)
  1804.         {
  1805.         // We're using direct color, so toss the table.
  1806.         ::DisposeCTable(pixMapPtr->pmTable);
  1807.         pixMapPtr->pmTable = NULL;
  1808.         }
  1809.     
  1810.     pixMapPtr->pmReserved = 0;
  1811.     
  1812.     //
  1813.     // Finally, set the pixel RGB color values.
  1814.     //
  1815.     
  1816.     UInt32*    pixelPtr = (UInt32*) imagePtr;
  1817.     UInt32    numPixels = imageSize.h * imageSize.v;
  1818.     SInt8*    indexPtr = imageColorIndexes;
  1819.     
  1820.     for (UInt32 pixelIndex = 0; pixelIndex < numPixels; pixelIndex++)
  1821.         {
  1822.         SInt8    rampIndex = *indexPtr++;
  1823.         
  1824.         if (rampIndex == OUT)
  1825.             *pixelPtr++ = 0x0000;
  1826.         else
  1827.             {
  1828.             RGBColor    rampColor = gAGARamp[rampIndex];
  1829.             
  1830.             //
  1831.             // Construct 32-bit color value.
  1832.             // Assuming red is RRrr, blue is BBbb, green is GGgg,
  1833.             // we want 0x00RRGGBB, using high byte of each color.
  1834.             // This way we toss the low-order (LSB) color data.
  1835.             //
  1836.  
  1837.             UInt32    pixelValue =
  1838.                     ((((UInt32) rampColor.red) & 0x0000FF00) << 8) |
  1839.                     (((UInt32) rampColor.green) & 0x0000FF00) |
  1840.                     ((((UInt32) rampColor.blue) & 0x0000FF00) >> 8);
  1841.  
  1842.             *pixelPtr++ = pixelValue;
  1843.             }
  1844.         }
  1845.  
  1846.     return noErr;
  1847.     }
  1848.  
  1849. void AGAOffscreenImage::DrawImage(SInt16 imageHOrigin, SInt16 imageVOrigin)
  1850.     {
  1851.     // Blast the offscreen image data into the current
  1852.     // port at the specified coordinate location.
  1853.  
  1854.     RGBColor    savedBackColor;
  1855.     GrafPtr        currentPort;
  1856.     Rect        outputRect = mImageSourceRect;
  1857.     
  1858.     ::GetBackColor(&savedBackColor);
  1859.     ::RGBBackColor(&gAGARamp[rW]);    // need white BG for desired CopyBits behavior
  1860.     
  1861.     ::OffsetRect(&outputRect, imageHOrigin, imageVOrigin);
  1862.     
  1863.     if (mClippingRegion != NULL)
  1864.         ::OffsetRgn(mClippingRegion, imageHOrigin, imageVOrigin);
  1865.  
  1866.     ::GetPort(¤tPort);
  1867.     ::CopyBits((BitMapPtr) *mImagePixMap,
  1868.         &(currentPort->portBits),
  1869.         &mImageSourceRect,
  1870.         &outputRect,
  1871.         srcCopy,
  1872.         mClippingRegion);
  1873.     
  1874.     if (mClippingRegion != NULL)
  1875.         ::OffsetRgn(mClippingRegion, - imageHOrigin, - imageVOrigin);
  1876.  
  1877.     ::RGBBackColor(&savedBackColor);
  1878.     }
  1879.  
  1880. void AGAOffscreenImage::DrawPattern(Rect* imageRect)
  1881.     {
  1882.     // Blast the offscreen image data into the current
  1883.     // port, starting at the specified coordinate location,
  1884.     // repeating tiled until the imageRect is filled.
  1885.  
  1886.     RGBColor    savedBackColor;
  1887.     GrafPtr        currentPort;
  1888.     Rect        outputRect;
  1889.     
  1890.     ::GetBackColor(&savedBackColor);
  1891.     ::RGBBackColor(&gAGARamp[rW]);    // need white BG for desired CopyBits behavior
  1892.     
  1893.     if (mClippingRegion != NULL)
  1894.         ::OffsetRgn(mClippingRegion, imageRect->left, imageRect->top);
  1895.  
  1896.     ::GetPort(¤tPort);
  1897.     
  1898.     outputRect.top = imageRect->top;
  1899.     outputRect.bottom = outputRect.top + mImageSourceRect.bottom;
  1900.  
  1901.     while (outputRect.top < imageRect->bottom)
  1902.         {
  1903.         outputRect.left = imageRect->left;
  1904.         outputRect.right = outputRect.left + mImageSourceRect.right;
  1905.         
  1906.         while (outputRect.left < imageRect->right)
  1907.             {
  1908.             ::CopyBits((BitMapPtr) *mImagePixMap,
  1909.                 &(currentPort->portBits),
  1910.                 &mImageSourceRect,
  1911.                 &outputRect,
  1912.                 srcCopy,
  1913.                 mClippingRegion);
  1914.             
  1915.             ::OffsetRect(&outputRect, mImageSourceRect.right, 0);
  1916.             }
  1917.  
  1918.         ::OffsetRect(&outputRect, 0, mImageSourceRect.bottom);
  1919.         }
  1920.  
  1921.     if (mClippingRegion != NULL)
  1922.         ::OffsetRgn(mClippingRegion, - imageRect->left, - imageRect->top);
  1923.  
  1924.     ::RGBBackColor(&savedBackColor);
  1925.     }
  1926.  
  1927. //
  1928. // AGARadioButton ---------------------------------------------------------------
  1929. //
  1930. // This class implements a standard radio button object,
  1931. // with the additional capabilities of automatic handling of
  1932. // radio group mutual exclusivity, and mixed state.
  1933. //
  1934.  
  1935. // Each radio button drawing state has an offscreen image.
  1936. AGAOffscreenImage*    AGARadioButton::mgOffscreenRadioImages[kNumRadioImages];
  1937.  
  1938. // These are the color ramp indexes that are used to build the offscreen images.
  1939. SInt8                AGARadioButton::kRadioImageValues[kNumRadioImages][kRadioImageHeight][kRadioImageWidth] =
  1940.     {
  1941.         {    // kRadioNormalOff
  1942.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1943.         { OUT, OUT,  rB, r10,  r2,  r2,  r2,  r4, r11,  rB, OUT, OUT },
  1944.         { OUT,  rB,  r4,  r2,  r1,  rW,  rW,  rW,  r2,  r7,  rB, OUT },
  1945.         {  r5, r10,  r2,  r1,  rW,  rW,  r1,  r1,  r2,  r4, r11,  r5 },
  1946.         { r11,  r2,  r1,  rW,  rW,  r1,  r1,  r2,  r2,  r4,  r7, r11 },
  1947.         {  rB,  r2,  rW,  rW,  r1,  r1,  r2,  r2,  r4,  r4,  r7,  rB },
  1948.         {  rB,  r2,  rW,  r1,  r1,  r2,  r2,  r4,  r4,  r5,  r7,  rB },
  1949.         { r11,  r4,  rW,  r1,  r2,  r2,  r4,  r4,  r5,  r5,  r7, r11 },
  1950.         {  r5, r10,  r2,  r2,  r2,  r4,  r4,  r5,  r5,  r7, r11,  r5 },
  1951.         { OUT,  rB,  r7,  r4,  r4,  r4,  r5,  r5,  r7,  r7,  rB, OUT },
  1952.         { OUT, OUT,  rB, r10,  r7,  r7,  r7,  r7, r11,  rB, OUT, OUT },
  1953.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1954.         },
  1955.  
  1956.         {    // kRadioNormalOn
  1957.         { OUT, OUT, OUT,  r5, r12,  rB,  rB, r12,  r5, OUT, OUT, OUT },
  1958.         { OUT, OUT, r12,  rB, r11, r10, r10, r10, r11,  rB, OUT, OUT },
  1959.         { OUT, r12, r11, r10,  r8,  r8,  r8,  r7,  r7,  r6,  rB, OUT },
  1960.         {  r5,  rB, r10,  r8,  rB,  rB,  rB,  rB,  r6,  r6, r11,  r5 },
  1961.         { r12, r11,  r8,  rB,  rB,  rB,  rB,  rB,  rB,  r6,  r4, r11 },
  1962.         {  rB, r10,  r8,  rB,  rB,  rB,  rB,  rB,  rB,  r4,  r4,  rB },
  1963.         {  rB, r10,  r8,  rB,  rB,  rB,  rB,  rB,  rB,  r4,  r2,  rB },
  1964.         { r12, r10,  r7,  rB,  rB,  rB,  rB,  rB,  rB,  r2,  rW, r11 },
  1965.         {  r5, r12,  r7,  r6,  rB,  rB,  rB,  rB,  r2,  rW, r11,  r5 },
  1966.         { OUT, r12,  r6,  r6,  r6,  r4,  r4,  r2,  rW,  rW,  rB, OUT },
  1967.         { OUT, OUT, r12, r11,  r4,  r4,  r2,  rW, r11,  rB, OUT, OUT },
  1968.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1969.         },
  1970.  
  1971.         {    // kRadioNormalMixed
  1972.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1973.         { OUT, OUT,  rB, r10,  r2,  r2,  r2,  r4, r11,  rB, OUT, OUT },
  1974.         { OUT,  rB,  r4,  r2,  r1,  rW,  rW,  rW,  r2,  r7,  rB, OUT },
  1975.         {  r5, r10,  r2,  r1,  rW,  rW,  r1,  r1,  r2,  r4, r11,  r5 },
  1976.         { r11,  r2,  r1,  rW,  rW,  r1,  r1,  r2,  r2,  r4,  r7, r11 },
  1977.         {  rB,  r2,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  r4,  r7,  rB },
  1978.         {  rB,  r2,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  r5,  r7,  rB },
  1979.         { r11,  r4,  rW,  r1,  r2,  r2,  r4,  r4,  r5,  r5,  r7, r11 },
  1980.         {  r5, r10,  r2,  r2,  r2,  r4,  r4,  r5,  r5,  r7, r11,  r5 },
  1981.         { OUT,  rB,  r7,  r4,  r4,  r4,  r5,  r5,  r7,  r7,  rB, OUT },
  1982.         { OUT, OUT,  rB, r10,  r7,  r7,  r7,  r7, r11,  rB, OUT, OUT },
  1983.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1984.         },
  1985.  
  1986.         {    // kRadioPressedOff
  1987.         { OUT, OUT, OUT,  r5, r12,  rB,  rB, r12,  r5, OUT, OUT, OUT },
  1988.         { OUT, OUT, r12,  rB, r11, r11, r11, r11, r11,  rB, OUT, OUT },
  1989.         { OUT, r12, r11, r11, r10, r10,  r9,  r9,  r9,  r8,  rB, OUT },
  1990.         {  r5,  rB, r11, r10, r10,  r9,  r9,  r8,  r8,  r8, r11,  r5 },
  1991.         { r12, r11, r10, r10,  r9,  r9,  r8,  r8,  r8,  r7,  r6, r11 },
  1992.         {  rB, r11, r10,  r9,  r9,  r8,  r8,  r8,  r7,  r7,  r6,  rB },
  1993.         {  rB, r11,  r9,  r9,  r8,  r8,  r8,  r7,  r7,  r6,  r6,  rB },
  1994.         { r12, r11,  r9,  r8,  r8,  r8,  r7,  r7,  r6,  r6,  r4, r11 },
  1995.         {  r5, r12,  r9,  r8,  r8,  r7,  r7,  r6,  r6,  r4, r10,  r5 },
  1996.         { OUT, r11,  r8,  r8,  r7,  r7,  r6,  r6,  r4,  r4,  rB, OUT },
  1997.         { OUT, OUT, r12, r11,  r6,  r6,  r6,  r4, r10,  rB, OUT, OUT },
  1998.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  1999.         },
  2000.  
  2001.         {    // kRadioPressedOn
  2002.         { OUT, OUT, OUT,  r5, r12,  rB,  rB, r12,  r5, OUT, OUT, OUT },
  2003.         { OUT, OUT, r12,  rB, r11, r11, r11, r11, r11,  rB, OUT, OUT },
  2004.         { OUT, r12, r11, r11, r10, r10,  r9,  r9,  r9,  r8,  rB, OUT },
  2005.         {  r5,  rB, r11, r10,  rB,  rB,  rB,  rB,  r8,  r8, r11,  r5 },
  2006.         { r12, r11, r10,  rB,  rB,  rB,  rB,  rB,  rB,  r7,  r6, r11 },
  2007.         {  rB, r11, r10,  rB,  rB,  rB,  rB,  rB,  rB,  r7,  r6,  rB },
  2008.         {  rB, r11,  r9,  rB,  rB,  rB,  rB,  rB,  rB,  r6,  r6,  rB },
  2009.         { r12, r11,  r9,  rB,  rB,  rB,  rB,  rB,  rB,  r6,  r4, r11 },
  2010.         {  r5, r12,  r9,  r8,  rB,  rB,  rB,  rB,  r6,  r4, r10,  r5 },
  2011.         { OUT, r11,  r8,  r8,  r7,  r7,  r6,  r6,  r4,  r4,  rB, OUT },
  2012.         { OUT, OUT, r12, r11,  r6,  r6,  r6,  r4, r10,  rB, OUT, OUT },
  2013.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  2014.         },
  2015.  
  2016.         {    // kRadioPressedMixed
  2017.         { OUT, OUT, OUT,  r5, r12,  rB,  rB, r12,  r5, OUT, OUT, OUT },
  2018.         { OUT, OUT, r12,  rB, r11, r11, r11, r11, r11,  rB, OUT, OUT },
  2019.         { OUT, r12, r11, r11, r10, r10,  r9,  r9,  r9,  r8,  rB, OUT },
  2020.         {  r5,  rB, r11, r10, r10,  r9,  r9,  r8,  r8,  r8, r11,  r5 },
  2021.         { r12, r11, r10, r10,  r9,  r9,  r8,  r8,  r8,  r7,  r6, r11 },
  2022.         {  rB, r11, r10,  rB,  rB,  rB,  rB,  rB,  rB,  r7,  r6,  rB },
  2023.         {  rB, r11,  r9,  rB,  rB,  rB,  rB,  rB,  rB,  r6,  r6,  rB },
  2024.         { r12, r11,  r9,  r8,  r8,  r8,  r7,  r7,  r6,  r6,  r4, r11 },
  2025.         {  r5, r12,  r9,  r8,  r8,  r7,  r7,  r6,  r6,  r4, r10,  r5 },
  2026.         { OUT, r11,  r8,  r8,  r7,  r7,  r6,  r6,  r4,  r4,  rB, OUT },
  2027.         { OUT, OUT, r12, r11,  r6,  r6,  r6,  r4, r10,  rB, OUT, OUT },
  2028.         { OUT, OUT, OUT,  r5, r11,  rB,  rB, r11,  r5, OUT, OUT, OUT },
  2029.         },
  2030.  
  2031.         {    // kRadioDisabledOff
  2032.         { OUT, OUT, OUT,  r4,  r7,  r7,  r7,  r7,  r4, OUT, OUT, OUT },
  2033.         { OUT, OUT,  r7,  r7,  r1,  r1,  r1,  r3,  r7,  r7, OUT, OUT },
  2034.         { OUT,  r7,  r3,  r1,  rW,  rW,  rW,  rW,  r1,  r5,  r7, OUT },
  2035.         {  r4,  r7,  r1,  rW,  rW,  rW,  rW,  rW,  r1,  r3,  r7,  r4 },
  2036.         {  r7,  r1,  rW,  rW,  rW,  rW,  rW,  r1,  r1,  r3,  r5,  r7 },
  2037.         {  r7,  r1,  rW,  rW,  rW,  rW,  r1,  r1,  r3,  r3,  r5,  r7 },
  2038.         {  r7,  r1,  rW,  rW,  rW,  r1,  r1,  r3,  r3,  r4,  r5,  r7 },
  2039.         {  r7,  r3,  rW,  rW,  r1,  r1,  r3,  r3,  r4,  r4,  r5,  r7 },
  2040.         {  r4,  r7,  r1,  r1,  r1,  r3,  r3,  r4,  r4,  r5,  r7,  r4 },
  2041.         { OUT,  r7,  r5,  r3,  r3,  r3,  r4,  r4,  r5,  r5,  r7, OUT },
  2042.         { OUT, OUT,  r7,  r7,  r5,  r5,  r5,  r5,  r7,  r7, OUT, OUT },
  2043.         { OUT, OUT, OUT,  r4,  r7,  r7,  r7,  r7,  r4, OUT, OUT, OUT },
  2044.         },
  2045.  
  2046.         {    // kRadioDisabledOn
  2047.         { OUT, OUT, OUT,  r2,  r7,  r7,  r7,  r7,  r2, OUT, OUT, OUT },
  2048.         { OUT, OUT,  r7,  r7,  r5,  r5,  r5,  r5,  r5,  r7, OUT, OUT },
  2049.         { OUT,  r7,  r5,  r5,  r4,  r4,  r4,  r3,  r3,  r3,  r7, OUT },
  2050.         {  r2,  r7,  r5,  r4,  r8,  r8,  r8,  r8,  r3,  r3,  r5,  r2 },
  2051.         {  r7,  r5,  r4,  r8,  r8,  r8,  r8,  r8,  r8,  r3,  r1,  r5 },
  2052.         {  r7,  r5,  r4,  r8,  r8,  r8,  r8,  r8,  r8,  r1,  r1,  r7 },
  2053.         {  r7,  r5,  r4,  r8,  r8,  r8,  r8,  r8,  r8,  r1,  rW,  r7 },
  2054.         {  r7,  r5,  r3,  r8,  r8,  r8,  r8,  r8,  r8,  rW,  rW,  r5 },
  2055.         {  r2,  r5,  r3,  r3,  r8,  r8,  r8,  r8,  rW,  rW,  r5,  r2 },
  2056.         { OUT,  r7,  r3,  r3,  r3,  r1,  r1,  rW,  rW,  rW,  r7, OUT },
  2057.         { OUT, OUT,  r7,  r7,  r1,  r1,  rW,  rW,  r5,  r7, OUT, OUT },
  2058.         { OUT, OUT, OUT,  r2,  r5,  r7,  r7,  r5,  r2, OUT, OUT, OUT },
  2059.         },
  2060.  
  2061.         {    // kRadioDisabledMixed
  2062.         { OUT, OUT, OUT,  r4,  r7,  r7,  r7,  r7,  r4, OUT, OUT, OUT },
  2063.         { OUT, OUT,  r7,  r7,  r1,  r1,  r1,  r3,  r7,  r7, OUT, OUT },
  2064.         { OUT,  r7,  r3,  r1,  rW,  rW,  rW,  rW,  r1,  r5,  r7, OUT },
  2065.         {  r4,  r7,  r1,  rW,  rW,  rW,  rW,  rW,  r1,  r3,  r7,  r4 },
  2066.         {  r7,  r1,  rW,  rW,  rW,  rW,  rW,  r1,  r1,  r3,  r5,  r7 },
  2067.         {  r7,  r1,  rW,  r8,  r8,  r8,  r8,  r8,  r8,  r3,  r5,  r7 },
  2068.         {  r7,  r1,  rW,  r8,  r8,  r8,  r8,  r8,  r8,  r4,  r5,  r7 },
  2069.         {  r7,  r3,  rW,  rW,  r1,  r1,  r3,  r3,  r4,  r4,  r5,  r7 },
  2070.         {  r4,  r7,  r1,  r1,  r1,  r3,  r3,  r4,  r4,  r5,  r7,  r4 },
  2071.         { OUT,  r7,  r5,  r3,  r3,  r3,  r4,  r4,  r5,  r5,  r7, OUT },
  2072.         { OUT, OUT,  r7,  r7,  r5,  r5,  r5,  r5,  r7,  r7, OUT, OUT },
  2073.         { OUT, OUT, OUT,  r4,  r7,  r7,  r7,  r7,  r4, OUT, OUT, OUT },
  2074.         }
  2075.  
  2076.     };
  2077.  
  2078. OSErr AGARadioButton::AllocateRadioImages()
  2079.     {
  2080.     // Allocate the offscreen image for each radio button state.
  2081.  
  2082.     OSErr    result = noErr;
  2083.     Point    imageSize;
  2084.     
  2085.     imageSize.h = kRadioImageWidth;
  2086.     imageSize.v = kRadioImageHeight;
  2087.     
  2088.     // A simple round rect defines the radio image clipping region.
  2089.  
  2090.     RgnHandle    radioImageClippingRegion = ::NewRgn();
  2091.     
  2092.     if (radioImageClippingRegion == NULL)
  2093.         result = memFullErr;
  2094.     else
  2095.         {
  2096.         Rect    imageClippingRect;
  2097.         
  2098.         ::SetRect(&imageClippingRect, 0, 0, kRadioImageWidth, kRadioImageHeight);
  2099.         ::OpenRgn();
  2100.         ::FrameRoundRect(&imageClippingRect, 11, 11);
  2101.         ::CloseRgn(radioImageClippingRegion);
  2102.         }
  2103.  
  2104.     for (UInt32 imageIndex = 0; imageIndex < kNumRadioImages; imageIndex++)
  2105.         {
  2106.         if (result == noErr)
  2107.             {
  2108.             mgOffscreenRadioImages[imageIndex] = new AGAOffscreenImage;
  2109.             
  2110.             result = mgOffscreenRadioImages[imageIndex]->CreateImageData(
  2111.                         imageSize,
  2112.                         &kRadioImageValues[imageIndex][0][0],
  2113.                         radioImageClippingRegion);
  2114.             }
  2115.         }
  2116.         
  2117.     if (radioImageClippingRegion != NULL)
  2118.         ::DisposeRgn(radioImageClippingRegion);
  2119.     
  2120.     return result;
  2121.     }
  2122.  
  2123. void AGARadioButton::DisposeRadioImages()
  2124.     {
  2125.     for (UInt32 imageIndex = 0; imageIndex < kNumRadioImages; imageIndex++)
  2126.         if (mgOffscreenRadioImages[imageIndex] != NULL)
  2127.             delete mgOffscreenRadioImages[imageIndex];
  2128.     }
  2129.  
  2130. AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
  2131. : AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
  2132.     {
  2133.     // Construct with initial empty button title.
  2134.  
  2135.     mValue = kRadioButtonOff;
  2136.     mAutomaticState = automaticState;
  2137.     mTitle[0];
  2138.     mTextStyle = textStyle;
  2139.     }
  2140.  
  2141. AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, StringPtr title, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
  2142. : AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
  2143.     {
  2144.     // Construct with specified button title.
  2145.  
  2146.     mValue = kRadioButtonOff;
  2147.     mAutomaticState = automaticState;
  2148.     PLstrcpy(mTitle, title);
  2149.     mTextStyle = textStyle;
  2150.     }
  2151.  
  2152. AGARadioButton::AGARadioButton(Rect* bounds, const AGATextStyle& textStyle, SInt16 stringListResourceID, SInt16 stringIndex, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
  2153. : AGAObject(bounds), MExclusiveObject(groupIDPart1, groupIDPart2)
  2154.     {
  2155.     // Construct by getting button title from specified resource.
  2156.  
  2157.     mValue = kRadioButtonOff;
  2158.     mAutomaticState = automaticState;
  2159.     ::GetIndString(mTitle, stringListResourceID, stringIndex);
  2160.     mTextStyle = textStyle;
  2161.     }
  2162.  
  2163. AGARadioButton::~AGARadioButton()
  2164.     {
  2165.     }
  2166.  
  2167. void AGARadioButton::DrawObject()
  2168.     {
  2169.     // Draw button in normal unpressed state.
  2170.  
  2171.     this->DrawButton(kNotPressed);
  2172.     }
  2173.  
  2174. Boolean AGARadioButton::TrackMouse(Point mouseLocation)
  2175.     {
  2176.     // If inherited tracking succeeded and we are set to
  2177.     // automatically change our state, toggle it.
  2178.  
  2179.     Boolean    wasItHit = AGAObject::TrackMouse(mouseLocation);
  2180.  
  2181.     if (wasItHit && mAutomaticState)
  2182.         this->SetValue(kRadioButtonOn, kRedraw);
  2183.  
  2184.     return wasItHit;
  2185.     }
  2186.  
  2187. void AGARadioButton::SetTitle(StringPtr title, Boolean redraw)
  2188.     {
  2189.     // Change button title, redraw if specified.
  2190.  
  2191.     PLstrcpy(mTitle, title);
  2192.     
  2193.     if (redraw)
  2194.         this->DrawObject();
  2195.     }
  2196.  
  2197. SInt32 AGARadioButton::GetValue()
  2198.     {
  2199.     // Return current state.
  2200.  
  2201.     return mValue;
  2202.     }
  2203.  
  2204. void AGARadioButton::SetValue(SInt32 newValue, Boolean redraw)
  2205.     {
  2206.     // Set current state, redraw if specified and necessary.
  2207.  
  2208.     if (newValue == kRadioButtonOn)
  2209.         gGroupsContainer->AGAHitGroupMember(this);
  2210.  
  2211.     if (newValue != mValue)
  2212.         {
  2213.         mValue = newValue;
  2214.         
  2215.         if (redraw)
  2216.             {
  2217.             this->DrawButton(kNotPressed);
  2218.             }
  2219.         }
  2220.     }
  2221.  
  2222. void AGARadioButton::TurnOff()
  2223.     {
  2224.     // Turn off the radio button, presumably in response
  2225.     // to another button in the group being turned on.
  2226.  
  2227.     this->SetValue(kRadioButtonOff, kRedraw);
  2228.     }
  2229.  
  2230. void AGARadioButton::DrawButton(Boolean pressed)
  2231.     {
  2232.     CleansePen();
  2233.  
  2234.     // Draw the button in the appropriate state.
  2235.  
  2236.     GDIterator    iter;
  2237.     Boolean        deep;
  2238.  
  2239.     while (iter.More(deep))
  2240.         {
  2241.         if (! mEnabled)
  2242.             this->DrawButtonDisabled(deep);
  2243.         else if (pressed)
  2244.             this->DrawButtonPressed(deep);
  2245.         else
  2246.             this->DrawButtonNormal(deep);
  2247.         }
  2248.  
  2249.     CleansePen();
  2250.     }
  2251.  
  2252. void AGARadioButton::SetTrackingState(Boolean isIn)
  2253.     {
  2254.     // Draw the button pressed or unpressed as specified.
  2255.  
  2256.     this->DrawButton(isIn);
  2257.     }
  2258.  
  2259. void AGARadioButton::DrawButtonNormal(Boolean deep)
  2260.     {
  2261.     Rect    r = mBounds;
  2262.  
  2263.     // Draw the button in enabled/unpressed state.
  2264.  
  2265.     if (deep)
  2266.         {
  2267.         if (mValue == kRadioButtonMixed)
  2268.             this->CopyImage(kRadioNormalMixed);
  2269.         else if (mValue == kRadioButtonOn)
  2270.             this->CopyImage(kRadioNormalOn);
  2271.         else
  2272.             this->CopyImage(kRadioNormalOff);
  2273.         }
  2274.     else
  2275.         {
  2276.         r.right = r.left + kRadioImageWidth;
  2277.         r.bottom = r.top + kRadioImageHeight;
  2278.  
  2279.         // Paint white over previous junk, if any.
  2280.         ::RGBForeColor(&gAGARamp[rW]);
  2281.         ::PaintRect(&r);
  2282.         // Paint frame.
  2283.         ::RGBForeColor(&gAGARamp[rB]);
  2284.         ::FrameOval(&r);
  2285.  
  2286.         // Draw dot or dash.
  2287.         if (mValue == kRadioButtonOn)
  2288.             {
  2289.             ::InsetRect(&r, 3, 3);
  2290.             ::PaintRoundRect(&r, 4, 4);
  2291.             }
  2292.         else if (mValue == kRadioButtonMixed)
  2293.             {
  2294.             ::PenSize(1, 2);
  2295.             ::MoveTo(r.left + 3, r.top + 5);
  2296.             ::Line(5, 0);
  2297.             }
  2298.         
  2299.         ::PenNormal();
  2300.         }
  2301.  
  2302.     // Draw the title.
  2303.     r = mBounds;
  2304.     r.left += (kRadioImageWidth + 6);
  2305.     r.bottom = r.top + kRadioImageHeight;
  2306.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
  2307.     }
  2308.  
  2309. void AGARadioButton::DrawButtonPressed(Boolean deep)
  2310.     {
  2311.     Rect    r = mBounds;
  2312.  
  2313.     // Draw the button in enabled/pressed state.
  2314.  
  2315.     if (deep)
  2316.         {
  2317.         if (mValue == kRadioButtonMixed)
  2318.             this->CopyImage(kRadioPressedMixed);
  2319.         else if (mValue == kRadioButtonOn)
  2320.             this->CopyImage(kRadioPressedOn);
  2321.         else
  2322.             this->CopyImage(kRadioPressedOff);
  2323.         }
  2324.     else
  2325.         {
  2326.         r.right = r.left + kRadioImageWidth;
  2327.         r.bottom = r.top + kRadioImageHeight;
  2328.  
  2329.         // Paint white over previous junk, if any.
  2330.         ::RGBForeColor(&gAGARamp[rW]);
  2331.         ::PaintRect(&r);
  2332.         // Paint frame.
  2333.         ::RGBForeColor(&gAGARamp[rB]);
  2334.         ::PenSize(2, 2);
  2335.         ::FrameOval(&r);
  2336.  
  2337.         // Draw check or dash.
  2338.         if (mValue == kRadioButtonOn)
  2339.             {
  2340.             ::InsetRect(&r, 3, 3);
  2341.             ::PaintRoundRect(&r, 4, 4);
  2342.             }
  2343.         else if (mValue == kRadioButtonMixed)
  2344.             {
  2345.             ::PenSize(1, 2);
  2346.             ::MoveTo(r.left + 3, r.top + 5);
  2347.             ::Line(5, 0);
  2348.             }
  2349.         
  2350.         ::PenNormal();
  2351.         }
  2352.  
  2353.     // Draw the title.
  2354.     r = mBounds;
  2355.     r.left += (kRadioImageWidth + 6);
  2356.     r.bottom = r.top + kRadioImageHeight;
  2357.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kNormalOutput, deep, mTextStyle);
  2358.     }
  2359.  
  2360. void AGARadioButton::DrawButtonDisabled(Boolean deep)
  2361.     {
  2362.     Rect    r = mBounds;
  2363.  
  2364.     // Draw the button in disabled/unpressed state.
  2365.  
  2366.     if (deep)
  2367.         {
  2368.         if (mValue == kRadioButtonMixed)
  2369.             this->CopyImage(kRadioDisabledMixed);
  2370.         else if (mValue == kRadioButtonOn)
  2371.             this->CopyImage(kRadioDisabledOn);
  2372.         else
  2373.             this->CopyImage(kRadioDisabledOff);
  2374.         }
  2375.     else
  2376.         {
  2377.         r.right = r.left + kRadioImageWidth;
  2378.         r.bottom = r.top + kRadioImageHeight;
  2379.  
  2380.         // Paint white over previous junk, if any.
  2381.         ::RGBForeColor(&gAGARamp[rW]);
  2382.         ::PaintRect(&r);
  2383.  
  2384.         // Paint frame.
  2385.         ::PenPat(&qd.gray);
  2386.         ::RGBForeColor(&gAGARamp[rB]);
  2387.         ::FrameOval(&r);
  2388.  
  2389.         // Draw check or dash.
  2390.         if (mValue == kRadioButtonOn)
  2391.             {
  2392.             ::InsetRect(&r, 3, 3);
  2393.             ::PaintRoundRect(&r, 4, 4);
  2394.             }
  2395.         else if (mValue == kRadioButtonMixed)
  2396.             {
  2397.             ::PenSize(1, 2);
  2398.             ::MoveTo(r.left + 3, r.top + 5);
  2399.             ::Line(5, 0);
  2400.             }
  2401.         
  2402.         ::PenNormal();
  2403.         }
  2404.  
  2405.     // Draw the title.
  2406.     r = mBounds;
  2407.     r.left += (kRadioImageWidth + 6);
  2408.     r.bottom = r.top + kRadioImageHeight;
  2409.     AGAStringOut(mTitle, &r, truncMiddle, teJustLeft, kDisabledOutput, deep, mTextStyle);
  2410.     }
  2411.  
  2412. void AGARadioButton::CopyImage(UInt32 index)
  2413.     {
  2414.     // Blast the specified offscreen image into the
  2415.     // radio button's button area.
  2416.  
  2417.     mgOffscreenRadioImages[index]->DrawImage(mBounds.left, mBounds.top);
  2418.     }
  2419.  
  2420. //
  2421. // MIconButtonObject ---------------------------------------------------------------
  2422. //
  2423. // This mixin class handles button drawing for the different types
  2424. // of icon button classes. This class draws the button, and subclasses
  2425. // for push/radio/checkbox that mix it in handle the behavioral aspects.
  2426. //
  2427. // Ideal button sizes, to match AGA specification:
  2428. // - Large icon button: 40x40 (32x32 iclx plus 4 pixel border on each side)
  2429. // - Small icon button: 22x22 (16x16 icsx plus 3 pixel border on each side)
  2430. // - Mini icon button:  16x16 (12x12 icmx plus 2 pixel border on each side)
  2431. // Note that mini icons are a rather rare resource that ResEdit 2.x doesn't grok.
  2432. //
  2433.  
  2434. MIconButtonObject::MIconButtonObject()
  2435.     {
  2436.     // Construct with no icon IDs.
  2437.  
  2438.     mOffIconID = kNoIconID;
  2439.     mOnIconID = kNoIconID;
  2440.     mIconType = kSmallIcon;
  2441.     }
  2442.  
  2443. MIconButtonObject::MIconButtonObject(SInt16 offIconID, SInt16 onIconID, UInt32 iconType)
  2444.     {
  2445.     // Construct with specified icon IDs.
  2446.  
  2447.     mOffIconID = offIconID;
  2448.     mOnIconID = onIconID;
  2449.     mIconType = iconType;
  2450.     }
  2451.  
  2452. MIconButtonObject::~MIconButtonObject()
  2453.     {
  2454.     }
  2455.  
  2456. void MIconButtonObject::SetIconIDs(SInt16 offIconID, SInt16 onIconID)
  2457.     {
  2458.     // Set icon IDs as specified.
  2459.  
  2460.     mOffIconID = offIconID;
  2461.     mOnIconID = onIconID;
  2462.     }
  2463.  
  2464. void MIconButtonObject::SetIconType(UInt32 iconType)
  2465.     {
  2466.     // Set icon type as specified.
  2467.  
  2468.     mIconType = iconType;
  2469.     }
  2470.  
  2471. void MIconButtonObject::DrawIconButton(Rect* bounds,
  2472.                                         Boolean isOn,
  2473.                                         Boolean isPressed,
  2474.                                         Boolean isEnabled,
  2475.                                         Boolean deep)
  2476.     {
  2477.     // Draw the icon button in the appropriate state.
  2478.  
  2479.     Rect                r = *bounds;
  2480.     IconTransformType    aTransform;
  2481.     
  2482.     if (deep)
  2483.         {
  2484.         if (isEnabled)
  2485.             ::RGBForeColor(&gAGARamp[rB]);
  2486.         else
  2487.             ::RGBForeColor(&gAGARamp[r8]);
  2488.  
  2489.         ::FrameRoundRect(&r, 4, 4);
  2490.         
  2491.         if (isPressed)
  2492.             {
  2493.             aTransform = ttSelected;
  2494.             ::RGBForeColor(&gAGARamp[r7]);
  2495.             }
  2496.         else if (isEnabled)
  2497.             {
  2498.             aTransform = ttNone;
  2499.  
  2500.             if (isOn)
  2501.                 ::RGBForeColor(&gAGARamp[r7]);
  2502.             else
  2503.                 ::RGBForeColor(&gAGARamp[r3]);
  2504.             }
  2505.         else
  2506.             {
  2507.             aTransform = ttDisabled;
  2508.  
  2509.             if (isOn)
  2510.                 ::RGBForeColor(&gAGARamp[r4]);
  2511.             else
  2512.                 ::RGBForeColor(&gAGARamp[r2]);
  2513.             }
  2514.  
  2515.         ::InsetRect(&r, 1, 1);
  2516.         ::PaintRect(&r);
  2517.         ::InsetRect(&r, -1, -1);
  2518.         }
  2519.     else
  2520.         {
  2521.         if (isPressed || isOn)
  2522.             ::RGBForeColor(&gAGARamp[rB]);
  2523.         else
  2524.             ::RGBForeColor(&gAGARamp[rW]);
  2525.  
  2526.         ::PaintRoundRect(&r, 4, 4);
  2527.         
  2528.         if (! isEnabled)
  2529.             ::PenPat(&qd.gray);
  2530.  
  2531.         ::RGBForeColor(&gAGARamp[rB]);
  2532.         ::FrameRoundRect(&r, 4, 4);
  2533.         ::PenNormal();
  2534.         
  2535.         if (isPressed)
  2536.             aTransform = ttSelected;
  2537.         else if (isEnabled)
  2538.             aTransform = ttNone;
  2539.         else
  2540.             aTransform = ttDisabled;
  2541.         }
  2542.     
  2543.     if (mIconType == kMiniIcon)
  2544.         this->DrawMiniEdges(bounds, isOn, isPressed, isEnabled, deep);
  2545.     else if (mIconType == kSmallIcon)
  2546.         this->DrawSmallEdges(bounds, isOn, isPressed, isEnabled, deep);
  2547.     else
  2548.         this->DrawLargeEdges(bounds, isOn, isPressed, isEnabled, deep);
  2549.  
  2550.     SInt16    halfIconSize;
  2551.     Point    buttonCenter;
  2552.     
  2553.     buttonCenter.h = r.left + ((r.right - r.left) / 2);
  2554.     buttonCenter.v = r.top + ((r.bottom - r.top) / 2);
  2555.  
  2556.     if (mIconType == kMiniIcon)
  2557.         halfIconSize = 6;    // 12x12 icm#
  2558.     else if (mIconType == kSmallIcon)
  2559.         halfIconSize = 8;    // 16x16 ics#
  2560.     else
  2561.         halfIconSize = 16;    // 32x32 icl#
  2562.  
  2563.     ::SetRect(&r, buttonCenter.h - halfIconSize,
  2564.                     buttonCenter.v - halfIconSize,
  2565.                     buttonCenter.h + halfIconSize,
  2566.                     buttonCenter.v + halfIconSize);
  2567.  
  2568.     SInt16    iconID = isOn ? mOnIconID : mOffIconID;
  2569.  
  2570.     if (iconID != kNoIconID)
  2571.         ::PlotIconID(&r, atNone, aTransform, iconID);
  2572.     }
  2573.  
  2574. void MIconButtonObject::DrawMiniEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled, Boolean deep)
  2575.     {
  2576.     // Draw the button edges as specified for a
  2577.     // "mini" sized button.
  2578.  
  2579.     enum { TL1, BR1, kNumEdgeColors };
  2580.  
  2581.     Rect    r = *bounds;
  2582.     UInt8    colorIndexes[kNumEdgeColors];
  2583.     
  2584.     if (deep)
  2585.         {
  2586.         if (isPressed || (isEnabled && isOn))
  2587.             {
  2588.             colorIndexes[TL1] = r10;
  2589.             colorIndexes[BR1] = r5;
  2590.             }
  2591.         else if (isEnabled)    // and it's off
  2592.             {
  2593.             colorIndexes[TL1] = rW;
  2594.             colorIndexes[BR1] = r6;
  2595.             }
  2596.         else if (isOn) // and it's disabled
  2597.             {
  2598.             colorIndexes[TL1] = r6;
  2599.             colorIndexes[BR1] = r2;
  2600.             }
  2601.         else    // it's off and disabled
  2602.             {
  2603.             colorIndexes[TL1] = r1;
  2604.             colorIndexes[BR1] = r5;
  2605.             }
  2606.         
  2607.         ::PenSize(1, 1);
  2608.  
  2609.         ::RGBForeColor(&gAGARamp[colorIndexes[TL1]]);
  2610.         ::MoveTo(r.left + 1, r.bottom - 3);
  2611.         ::LineTo(r.left + 1, r.top + 1);
  2612.         ::LineTo(r.right - 3, r.top + 1);
  2613.  
  2614.         ::RGBForeColor(&gAGARamp[colorIndexes[BR1]]);
  2615.         ::MoveTo(r.left + 2, r.bottom - 2);
  2616.         ::LineTo(r.right - 2, r.bottom - 2);
  2617.         ::LineTo(r.right - 2, r.top + 2);
  2618.         }
  2619.     else if (isPressed)
  2620.         {
  2621.         ::RGBForeColor(&gAGARamp[rB]);
  2622.         ::PaintRoundRect(&r, 4, 4);
  2623.         }
  2624.     }
  2625.  
  2626. void MIconButtonObject::DrawSmallEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled, Boolean deep)
  2627.     {
  2628.     // Draw the button edges as specified for a
  2629.     // "small" sized button.
  2630.  
  2631.     enum { TL1, TL2, BR1, BR2, kNumEdgeColors };
  2632.  
  2633.     Rect    r = *bounds;
  2634.     UInt8    colorIndexes[kNumEdgeColors];
  2635.     
  2636.     if (deep)
  2637.         {
  2638.         if (isPressed || (isEnabled && isOn))
  2639.             {
  2640.             colorIndexes[TL1] = r11;
  2641.             colorIndexes[TL2] = r9;
  2642.             colorIndexes[BR1] = r4;
  2643.             colorIndexes[BR2] = r6;
  2644.             }
  2645.         else if (isEnabled)    // and it's off
  2646.             {
  2647.             colorIndexes[TL1] = r3;
  2648.             colorIndexes[TL2] = rW;
  2649.             colorIndexes[BR1] = r8;
  2650.             colorIndexes[BR2] = r5;
  2651.             }
  2652.         else if (isOn) // and it's disabled
  2653.             {
  2654.             colorIndexes[TL1] = r6;
  2655.             colorIndexes[TL2] = r5;
  2656.             colorIndexes[BR1] = r2;
  2657.             colorIndexes[BR2] = r3;
  2658.             }
  2659.         else    // it's off and disabled
  2660.             {
  2661.             colorIndexes[TL1] = r2;
  2662.             colorIndexes[TL2] = r1;
  2663.             colorIndexes[BR1] = r5;
  2664.             colorIndexes[BR2] = r4;
  2665.             }
  2666.         
  2667.         ::PenSize(1, 1);
  2668.  
  2669.         ::RGBForeColor(&gAGARamp[colorIndexes[TL1]]);
  2670.         ::MoveTo(r.left + 1, r.bottom - 3);
  2671.         ::LineTo(r.left + 1, r.top + 1);
  2672.         ::LineTo(r.right - 3, r.top + 1);
  2673.  
  2674.         ::RGBForeColor(&gAGARamp[colorIndexes[TL2]]);
  2675.         ::MoveTo(r.left + 2, r.bottom - 4);
  2676.         ::LineTo(r.left + 2, r.top + 2);
  2677.         ::LineTo(r.right - 4, r.top + 2);
  2678.  
  2679.         ::RGBForeColor(&gAGARamp[colorIndexes[BR1]]);
  2680.         ::MoveTo(r.left + 2, r.bottom - 2);
  2681.         ::LineTo(r.right - 2, r.bottom - 2);
  2682.         ::LineTo(r.right - 2, r.top + 2);
  2683.  
  2684.         ::RGBForeColor(&gAGARamp[colorIndexes[BR2]]);
  2685.         ::MoveTo(r.left + 3, r.bottom - 3);
  2686.         ::LineTo(r.right - 3, r.bottom - 3);
  2687.         ::LineTo(r.right - 3, r.top + 3);
  2688.         }
  2689.     else if (isPressed)
  2690.         {
  2691.         ::RGBForeColor(&gAGARamp[rB]);
  2692.         ::PaintRoundRect(&r, 4, 4);
  2693.         }
  2694.     }
  2695.  
  2696. void MIconButtonObject::DrawLargeEdges(Rect* bounds, Boolean isOn, Boolean isPressed, Boolean isEnabled, Boolean deep)
  2697.     {
  2698.     // Draw the button edges as specified for a
  2699.     // "large" sized button.
  2700.  
  2701.     enum { TL1, TL2, TL3, BR1, BR2, BR3, kNumEdgeColors };
  2702.  
  2703.     Rect    r = *bounds;
  2704.     UInt8    colorIndexes[kNumEdgeColors];
  2705.     
  2706.     if (deep)
  2707.         {
  2708.         if (isPressed || (isEnabled && isOn))
  2709.             {
  2710.             colorIndexes[TL1] = r12;
  2711.             colorIndexes[TL2] = r11;
  2712.             colorIndexes[TL3] = r9;
  2713.             colorIndexes[BR1] = r4;
  2714.             colorIndexes[BR2] = r5;
  2715.             colorIndexes[BR3] = r6;
  2716.             }
  2717.         else if (isEnabled)    // and it's off
  2718.             {
  2719.             colorIndexes[TL1] = r3;
  2720.             colorIndexes[TL2] = r1;
  2721.             colorIndexes[TL3] = rW;
  2722.             colorIndexes[BR1] = r11;
  2723.             colorIndexes[BR2] = r9;
  2724.             colorIndexes[BR3] = r5;
  2725.             }
  2726.         else if (isOn) // and it's disabled
  2727.             {
  2728.             colorIndexes[TL1] = r7;
  2729.             colorIndexes[TL2] = r6;
  2730.             colorIndexes[TL3] = r5;
  2731.             colorIndexes[BR1] = r1;
  2732.             colorIndexes[BR2] = r2;
  2733.             colorIndexes[BR3] = r3;
  2734.             }
  2735.         else    // it's off and disabled
  2736.             {
  2737.             colorIndexes[TL1] = r3;
  2738.             colorIndexes[TL2] = r1;
  2739.             colorIndexes[TL3] = rW;
  2740.             colorIndexes[BR1] = r6;
  2741.             colorIndexes[BR2] = r5;
  2742.             colorIndexes[BR3] = r4;
  2743.             }
  2744.         
  2745.         ::PenSize(1, 1);
  2746.  
  2747.         ::RGBForeColor(&gAGARamp[colorIndexes[TL1]]);
  2748.         ::MoveTo(r.left + 1, r.bottom - 3);
  2749.         ::LineTo(r.left + 1, r.top + 1);
  2750.         ::LineTo(r.right - 3, r.top + 1);
  2751.  
  2752.         ::RGBForeColor(&gAGARamp[colorIndexes[TL2]]);
  2753.         ::MoveTo(r.left + 2, r.bottom - 4);
  2754.         ::LineTo(r.left + 2, r.top + 2);
  2755.         ::LineTo(r.right - 4, r.top + 2);
  2756.  
  2757.         ::RGBForeColor(&gAGARamp[colorIndexes[TL3]]);
  2758.         ::MoveTo(r.left + 3, r.bottom - 5);
  2759.         ::LineTo(r.left + 3, r.top + 3);
  2760.         ::LineTo(r.right - 5, r.top + 3);
  2761.  
  2762.         ::RGBForeColor(&gAGARamp[colorIndexes[BR1]]);
  2763.         ::MoveTo(r.left + 2, r.bottom - 2);
  2764.         ::LineTo(r.right - 2, r.bottom - 2);
  2765.         ::LineTo(r.right - 2, r.top + 2);
  2766.  
  2767.         ::RGBForeColor(&gAGARamp[colorIndexes[BR2]]);
  2768.         ::MoveTo(r.left + 3, r.bottom - 3);
  2769.         ::LineTo(r.right - 3, r.bottom - 3);
  2770.         ::LineTo(r.right - 3, r.top + 3);
  2771.  
  2772.         ::RGBForeColor(&gAGARamp[colorIndexes[BR3]]);
  2773.         ::MoveTo(r.left + 4, r.bottom - 4);
  2774.         ::LineTo(r.right - 4, r.bottom - 4);
  2775.         ::LineTo(r.right - 4, r.top + 4);
  2776.         }
  2777.     else if (isPressed)
  2778.         {
  2779.         ::RGBForeColor(&gAGARamp[rB]);
  2780.         ::PaintRoundRect(&r, 4, 4);
  2781.         }
  2782.     }
  2783.  
  2784. UInt32 MIconButtonObject::GetDefaultIconType(SInt16 width)
  2785.     {
  2786.     if (width > 39)
  2787.         return kLargeIcon;
  2788.     else if (width > 21)
  2789.         return kSmallIcon;
  2790.     else
  2791.         return kMiniIcon;
  2792.     }
  2793.  
  2794.  
  2795. //
  2796. // AGAIconPushButton ---------------------------------------------------------------
  2797. //
  2798. // This class implements an icon-based pushbutton object, such as
  2799. // a toolbar icon command button.
  2800. //
  2801.  
  2802. AGAIconPushButton::AGAIconPushButton(Rect* bounds)
  2803. : AGAPushButton(bounds, gAGAStdSystemStyle), MIconButtonObject()
  2804.     {
  2805.     // Just call through to mixed in constructors.
  2806.     }
  2807.  
  2808. AGAIconPushButton::AGAIconPushButton(Rect* bounds, SInt16 iconID, UInt32 iconType)
  2809. : AGAPushButton(bounds, gAGAStdSystemStyle), MIconButtonObject(iconID, iconID, iconType)
  2810.     {
  2811.     // Just call through to mixed in constructors.
  2812.     }
  2813.  
  2814. AGAIconPushButton::~AGAIconPushButton()
  2815.     {
  2816.     }
  2817.  
  2818. void AGAIconPushButton::DrawButtonNormal(Boolean deep)
  2819.     {
  2820.     // Call icon button parent class with appropriate parameters.
  2821.  
  2822.     MIconButtonObject::DrawIconButton(&mBounds, FALSE, kNotPressed, kEnabled, deep);
  2823.     }
  2824.  
  2825. void AGAIconPushButton::DrawButtonPressed(Boolean deep)
  2826.     {
  2827.     // Call icon button parent class with appropriate parameters.
  2828.  
  2829.     MIconButtonObject::DrawIconButton(&mBounds, FALSE, kPressed, kEnabled, deep);
  2830.     }
  2831.  
  2832. void AGAIconPushButton::DrawButtonDisabled(Boolean deep)
  2833.     {
  2834.     // Call icon button parent class with appropriate parameters.
  2835.  
  2836.     MIconButtonObject::DrawIconButton(&mBounds, FALSE, kNotPressed, kDisabled, deep);
  2837.     }
  2838.  
  2839. //
  2840. // AGAIconCheckBox ---------------------------------------------------------------
  2841. //
  2842. // This class implements an icon-based checkbox object, such as
  2843. // a toolbar icon on/off button.
  2844. //
  2845.  
  2846. AGAIconCheckBox::AGAIconCheckBox(Rect* bounds, Boolean automaticState)
  2847. : AGACheckBox(bounds, gAGAStdSystemStyle, automaticState), MIconButtonObject()
  2848.     {
  2849.     // Just call through to mixed in constructors.
  2850.     }
  2851.  
  2852. AGAIconCheckBox::AGAIconCheckBox(Rect* bounds, Boolean automaticState, SInt16 offIconID, SInt16 onIconID, UInt32 iconType)
  2853. : AGACheckBox(bounds, gAGAStdSystemStyle, automaticState), MIconButtonObject(offIconID, onIconID, iconType)
  2854.     {
  2855.     // Just call through to mixed in constructors.
  2856.     }
  2857.  
  2858. AGAIconCheckBox::~AGAIconCheckBox()
  2859.     {
  2860.     }
  2861.  
  2862. void AGAIconCheckBox::DrawButtonNormal(Boolean deep)
  2863.     {
  2864.     // Call icon button parent class with appropriate parameters.
  2865.  
  2866.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kNotPressed, kEnabled, deep);
  2867.     }
  2868.  
  2869. void AGAIconCheckBox::DrawButtonPressed(Boolean deep)
  2870.     {
  2871.     // Call icon button parent class with appropriate parameters.
  2872.  
  2873.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kPressed, kEnabled, deep);
  2874.     }
  2875.  
  2876. void AGAIconCheckBox::DrawButtonDisabled(Boolean deep)
  2877.     {
  2878.     // Call icon button parent class with appropriate parameters.
  2879.  
  2880.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kCheckBoxOff, kNotPressed, kDisabled, deep);
  2881.     }
  2882.  
  2883. //
  2884. // AGAIconRadioButton ---------------------------------------------------------------
  2885. //
  2886. // This class implements an icon-based pushbutton object, such as
  2887. // a toolbar icon XOR group member button.
  2888. //
  2889.  
  2890. AGAIconRadioButton::AGAIconRadioButton(Rect* bounds, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState)
  2891. : AGARadioButton(bounds, gAGAStdSystemStyle, groupIDPart1, groupIDPart2, automaticState), MIconButtonObject()
  2892.     {
  2893.     // Just call through to mixed in constructors.
  2894.     }
  2895.  
  2896. AGAIconRadioButton::AGAIconRadioButton(Rect* bounds, UInt32 groupIDPart1, UInt32 groupIDPart2, Boolean automaticState, SInt16 offIconID, SInt16 onIconID, UInt32 iconType)
  2897. : AGARadioButton(bounds, gAGAStdSystemStyle, groupIDPart1, groupIDPart2, automaticState), MIconButtonObject(offIconID, onIconID, iconType)
  2898.     {
  2899.     // Just call through to mixed in constructors.
  2900.     }
  2901.  
  2902. AGAIconRadioButton::~AGAIconRadioButton()
  2903.     {
  2904.     }
  2905.  
  2906. void AGAIconRadioButton::DrawButtonNormal(Boolean deep)
  2907.     {
  2908.     // Call icon button parent class with appropriate parameters.
  2909.  
  2910.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kNotPressed, kEnabled, deep);
  2911.     }
  2912.  
  2913. void AGAIconRadioButton::DrawButtonPressed(Boolean deep)
  2914.     {
  2915.     // Call icon button parent class with appropriate parameters.
  2916.  
  2917.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kPressed, kEnabled, deep);
  2918.     }
  2919.  
  2920. void AGAIconRadioButton::DrawButtonDisabled(Boolean deep)
  2921.     {
  2922.     // Call icon button parent class with appropriate parameters.
  2923.  
  2924.     MIconButtonObject::DrawIconButton(&mBounds, mValue != kRadioButtonOff, kNotPressed, kDisabled, deep);
  2925.     }
  2926.  
  2927. //
  2928. // AGATrackingIndicator ---------------------------------------------------------------
  2929. //
  2930. // This is the abstract superclass for scroll bars and sliders.
  2931. // They all have a range, and a value shown by a draggable indicator.
  2932. //
  2933.  
  2934. #pragma segment GrayCouncilCore2
  2935.  
  2936. AGATrackingIndicator::AGATrackingIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue)
  2937.     : AGAObject(bounds)
  2938.     {
  2939.     // Construct with default options.
  2940.  
  2941.     mMinimum = minimum;
  2942.     mMaximum = maximum;
  2943.     mValue = initialValue;
  2944.     
  2945.     mPageSize = 1;
  2946.     mGhostValue = mValue;
  2947.     mLiveTracking = FALSE;
  2948.     mIsProportional = FALSE;
  2949.     mIsHorizontal = (bounds->right - bounds->left) > (bounds->bottom - bounds->top);
  2950.     mIsPressed = FALSE;
  2951.     
  2952.     mNotificationRoutine = NULL;
  2953.     }
  2954.  
  2955. AGATrackingIndicator::AGATrackingIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, SInt32 pageSize, Boolean liveTracking, Boolean proportional)
  2956.     : AGAObject(bounds)
  2957.     {
  2958.     // Construct with specified options.
  2959.  
  2960.     mMinimum = minimum;
  2961.     mMaximum = maximum;
  2962.     mValue = initialValue;
  2963.     mPageSize = pageSize;
  2964.     mGhostValue = mValue;
  2965.     mLiveTracking = liveTracking;
  2966.     mIsProportional = proportional;
  2967.     mIsHorizontal = (bounds->right - bounds->left) > (bounds->bottom - bounds->top);
  2968.     mIsPressed = FALSE;
  2969.     
  2970.     mNotificationRoutine = NULL;
  2971.     }
  2972.  
  2973. AGATrackingIndicator::~AGATrackingIndicator()
  2974.     {
  2975.     }
  2976.  
  2977. void AGATrackingIndicator::InstallNotificationRoutine(AGATrackingIndicatorNotifyPtr notificationRoutine, void* userData)
  2978.     {
  2979.     // Install the supplied function pointer and user data to
  2980.     // be called during notification.
  2981.  
  2982.     mNotificationRoutine = notificationRoutine;
  2983.     mUserData = userData;
  2984.     }
  2985.  
  2986. void AGATrackingIndicator::SetAttributes(Boolean isHorizontal, Boolean liveTracking, Boolean isProportional)
  2987.     {
  2988.     // Set options as specified.
  2989.  
  2990.     mIsHorizontal = isHorizontal;
  2991.     mLiveTracking = liveTracking;
  2992.     mIsProportional = isProportional;
  2993.     }
  2994.  
  2995. void AGATrackingIndicator::DrawObject()
  2996.     {
  2997.     // Call component drawing functions. These are all overridden
  2998.     // by subclasses.
  2999.  
  3000.     this->DrawBackground();
  3001.     this->DrawIndicatorTrack();
  3002.     this->DrawTrackEnds();
  3003.     this->DrawIndicator();
  3004.     }
  3005.  
  3006. Boolean AGATrackingIndicator::TrackMouse(Point mouseLocation)
  3007.     {
  3008.     // Track the mouse and return true if the indicator
  3009.     // value was changed.
  3010.  
  3011.     return this->TrackPart(mouseLocation, this->TrackTestPart(mouseLocation));
  3012.     }
  3013.  
  3014. Boolean AGATrackingIndicator::TrackPart(Point mouseLocation, SInt32 partHit)
  3015.     {
  3016.     // Track the mouse in the specified part and return true
  3017.     // if the indicator value was changed.
  3018.  
  3019.     if (partHit != kIndicatorPress)
  3020.         return FALSE;
  3021.  
  3022.     SInt32    originalValue = mValue;
  3023.     Point    oldPoint = mouseLocation;
  3024.     Point    newPoint = mouseLocation;
  3025.     SInt32    oldValue = originalValue;
  3026.     SInt32    newValue = originalValue;
  3027.     Boolean    isButtonDown = TRUE;    // ensure at least one time through
  3028.     
  3029.     mGhostValue = mValue;
  3030.     mIsPressed = TRUE;
  3031.     this->DrawIndicator();    // will draw it pressed
  3032.     
  3033.     while (isButtonDown)
  3034.         {
  3035.         ::GetMouse(&newPoint);    // gives local coordinates
  3036.         
  3037.         if (this->IsValidIndicatorTrackMouse(newPoint) &&
  3038.             ! ::EqualPt(newPoint, oldPoint))
  3039.             {
  3040.             newValue = this->GetValueFromMouseDelta(oldValue, mouseLocation, newPoint);
  3041.         
  3042.             if (mLiveTracking)
  3043.                 {
  3044.                 SInt32    oldValue = mValue;
  3045.  
  3046.                 this->SetValue(newValue, kRedraw);
  3047.                 
  3048.                 if (mValue != oldValue)
  3049.                     this->NotifyValue();
  3050.                 }
  3051.             else
  3052.                 this->SetGhostValue(newValue, kRedraw);
  3053.             
  3054.             oldPoint = newPoint;
  3055.             }
  3056.         
  3057.         isButtonDown = ::StillDown();
  3058.         }
  3059.     
  3060.     mIsPressed = FALSE;
  3061.     
  3062.     if (mLiveTracking)
  3063.         this->DrawIndicator();    // unpressed
  3064.     else
  3065.         {
  3066.         this->RemoveGhost(newValue);
  3067.         this->DrawIndicator();    // unpressed
  3068.  
  3069.         if (newValue != mValue)    // don't notify if no change
  3070.             {
  3071.             this->SetValue(newValue, kRedraw);    // will draw new indicator
  3072.             this->NotifyValue();
  3073.             }
  3074.         }
  3075.     
  3076.     return (mValue != originalValue);
  3077.     }
  3078.  
  3079. SInt32 AGATrackingIndicator::GetValue()
  3080.     {
  3081.     // Return the current indicator value.
  3082.  
  3083.     return mValue;
  3084.     }
  3085.  
  3086. void AGATrackingIndicator::SetGhostValue(SInt32 newValue, Boolean redraw)
  3087.     {
  3088.     // Set the ghost indicator value, and optionally redraw it
  3089.     // at its new position.
  3090.  
  3091.     if (newValue > mMaximum)
  3092.         newValue = mMaximum;
  3093.     else if (newValue < mMinimum)
  3094.         newValue = mMinimum;
  3095.  
  3096.     if (newValue != mGhostValue)
  3097.         {
  3098.         if (redraw)
  3099.             this->RemoveGhost(newValue);
  3100.  
  3101.         mGhostValue = newValue;
  3102.         
  3103.         if (redraw)
  3104.             this->DrawGhost();
  3105.         }
  3106.     }
  3107.  
  3108. void AGATrackingIndicator::SetValue(SInt32 newValue, Boolean redraw)
  3109.     {
  3110.     // Set the indicator value, and optionally redraw it
  3111.     // at its new position.
  3112.  
  3113.     if (newValue > mMaximum)
  3114.         newValue = mMaximum;
  3115.     else if (newValue < mMinimum)
  3116.         newValue = mMinimum;
  3117.  
  3118.     if (newValue != mValue)
  3119.         {
  3120.         if (redraw)
  3121.             this->RemoveIndicator(newValue);
  3122.  
  3123.         mValue = newValue;
  3124.         
  3125.         if (redraw)
  3126.             this->DrawIndicator();
  3127.         }
  3128.     }
  3129.  
  3130. void AGATrackingIndicator::GetRange(SInt32* minimum, SInt32* maximum)
  3131.     {
  3132.     // Return the current min/max range.
  3133.  
  3134.     *minimum = mMinimum;
  3135.     *maximum = mMaximum;
  3136.     }
  3137.  
  3138. void AGATrackingIndicator::SetRange(SInt32 newMinimum, SInt32 newMaximum, Boolean redraw)
  3139.     {
  3140.     // Set the min/max range, and optionally redraw.
  3141.  
  3142.     if ((newMinimum != mMinimum) ||
  3143.         (newMaximum != mMaximum))
  3144.         {
  3145.         if (redraw)
  3146.             this->RemoveIndicator(mValue);
  3147.  
  3148.         mMinimum = newMinimum;
  3149.         mMaximum = newMaximum;
  3150.  
  3151.         if (redraw)
  3152.             this->DrawIndicator();
  3153.         }
  3154.     }
  3155.  
  3156. SInt32 AGATrackingIndicator::GetPageSize()
  3157.     {
  3158.     // Return the current indicator page size.
  3159.  
  3160.     return mPageSize;
  3161.     }
  3162.  
  3163. void AGATrackingIndicator::SetPageSize(SInt32 newPageSize, Boolean redraw)
  3164.     {
  3165.     // Set the indicator page size. Redraw is not
  3166.     // necessary if the indicator is not proportional.
  3167.  
  3168.     if (newPageSize != mPageSize)
  3169.         {
  3170.         if (redraw && mIsProportional)
  3171.             this->RemoveIndicator(mValue);
  3172.  
  3173.         mPageSize = newPageSize;
  3174.         
  3175.         if (redraw && mIsProportional)
  3176.             this->DrawIndicator();
  3177.         }
  3178.     }
  3179.  
  3180. SInt32 AGATrackingIndicator::TrackTestPart(Point mouseLocation)
  3181.     {
  3182.     // Must be overridden. Return the part value that the
  3183.     // specified mouse position would hit.
  3184.  
  3185.     return kNoTrackPress;
  3186.     }
  3187.  
  3188. Boolean AGATrackingIndicator::IsValidIndicatorTrackMouse(Point mouseLocation)
  3189.     {
  3190.     // Usually overridden. Return true if the specified mouse
  3191.     // position should be considered "in" for tracking purposes
  3192.     // after the initial hit has succeeded. Return false if the
  3193.     // specified mouse position is too far away from the control
  3194.     // to use it for the next momentary tracking position.
  3195.  
  3196.     return ::PtInRect(mouseLocation, &mBounds);
  3197.     }
  3198.  
  3199. SInt32 AGATrackingIndicator::GetValueFromMouseDelta(SInt32 originalValue, Point originalMouseLocation, Point newMouseLocation)
  3200.     {
  3201.     // Must be overridden. Return the indicator value that should be
  3202.     // applied assuming the supplied starting value and mouse hit point,
  3203.     // and the supplied current mouse tracking location.
  3204.     return originalValue;
  3205.     }
  3206.  
  3207. void AGATrackingIndicator::DrawBackground()
  3208.     {
  3209.     // Override to paint the background area so that the
  3210.     // indicator drawn at its old position will be wiped out.
  3211.     // Clipping will be already set up to avoid excess flicker.
  3212.     }
  3213.  
  3214. void AGATrackingIndicator::DrawIndicatorTrack()
  3215.     {
  3216.     // Override to draw the empty indicator track. Must include
  3217.     // all possible indicator coverage.
  3218.     }
  3219.  
  3220. void AGATrackingIndicator::DrawTrackEnds()
  3221.     {
  3222.     // Override to draw the track ends outside the possible
  3223.     // indicator coverage if not drawn in DrawIndicatorTrack.
  3224.     }
  3225.  
  3226. void AGATrackingIndicator::DrawIndicator()
  3227.     {
  3228.     // Override to draw the indicator at its current value/state.
  3229.     }
  3230.  
  3231. void AGATrackingIndicator::RemoveIndicator(SInt32 newValue)
  3232.     {
  3233.     // Override to draw/erase whatever is needed to remove the
  3234.     // current indicator in preparation for being drawn at
  3235.     // the specified new value. The new value is supplied so
  3236.     // that erasing can be kept to a minimal area.
  3237.     }
  3238.  
  3239. void AGATrackingIndicator::DrawGhost()
  3240.     {
  3241.     // Override to draw the indicator in ghost mode at
  3242.     // the current ghost value.
  3243.     }
  3244.  
  3245. void AGATrackingIndicator::RemoveGhost(SInt32 newValue)
  3246.     {
  3247.     // Override to draw/erase whatever is needed to remove the
  3248.     // ghost indicator in preparation for being drawn at
  3249.     // the specified new value. The new value is supplied so
  3250.     // that erasing can be kept to a minimal area.
  3251.     }
  3252.  
  3253. void AGATrackingIndicator::NotifyValue()
  3254.     {
  3255.     // Call the installed notification routine, if any, with
  3256.     // the installed user data and our new value.
  3257.  
  3258.     if (mNotificationRoutine != NULL)
  3259.         (*(mNotificationRoutine))(this, mValue, mUserData);
  3260.     }
  3261.  
  3262. //
  3263. // AGAScrollBar ---------------------------------------------------------------
  3264. //
  3265. // This class implements a standard AGA scroll bar, with the additional
  3266. // ability to perform live tracking and a proportional thumb.
  3267. //
  3268.  
  3269. // These regions are used momentarily while tracking the scroll
  3270. // bar indicator to clip and optimize redrawing.
  3271. RgnHandle AGAScrollBar::mgSavedIndicatorClip = ::NewRgn();
  3272. RgnHandle AGAScrollBar::mgOldIndicatorClip = ::NewRgn();
  3273. RgnHandle AGAScrollBar::mgNewIndicatorClip = ::NewRgn();
  3274.  
  3275. AGAScrollBar::AGAScrollBar(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue)
  3276.     : AGATrackingIndicator(bounds, minimum, maximum, initialValue)
  3277.     {
  3278.     // Construct with default options.
  3279.     mLiveTracking = TestGrayCouncilDefault(kAGALiveScrolling);
  3280.     mIsProportional = TestGrayCouncilDefault(kAGAProportionalScrolling);
  3281.  
  3282.     mSingleStepSize = 1;
  3283.     mPageStepSize = 1;
  3284.     mActive = TRUE;
  3285.     }
  3286.  
  3287. AGAScrollBar::AGAScrollBar(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, SInt32 singleStepSize, SInt32 pageStepSize, SInt32 pageSize, Boolean liveTracking, Boolean proportional)
  3288.     : AGATrackingIndicator(bounds, minimum, maximum, initialValue, pageSize, liveTracking, proportional)
  3289.     {
  3290.     // Construct with specified options.
  3291.  
  3292.     mSingleStepSize = singleStepSize;
  3293.     mPageStepSize = pageStepSize;
  3294.     mActive = TRUE;
  3295.     }
  3296.  
  3297. AGAScrollBar::~AGAScrollBar()
  3298.     {
  3299.     }
  3300.  
  3301. void AGAScrollBar::SetStepSizes(SInt32 singleStepSize, SInt32 pageStepSize)
  3302.     {
  3303.     // Set the scrolling step delta amounts.
  3304.  
  3305.     mSingleStepSize = singleStepSize;
  3306.     mPageStepSize = pageStepSize;
  3307.     }
  3308.  
  3309. void AGAScrollBar::Activate(Boolean activateState, Boolean redraw)
  3310.     {
  3311.     // Set the active/inactive state. Scroll bars are the
  3312.     // only control that have a different appearance when
  3313.     // in an inactive window.
  3314.  
  3315.     mActive = activateState;
  3316.     
  3317.     if (redraw)
  3318.         this->DrawObject();
  3319.     }
  3320.  
  3321. Boolean AGAScrollBar::TrackPart(Point mouseLocation, SInt32 partHit)
  3322.     {
  3323.     // Track the mouse and return true if tracking changed the
  3324.     // indicator value. Thumb tracking is handled by superclass.
  3325.     // Scroll bar just handles arrow and page tracking.
  3326.  
  3327.     if ((partHit != kArrowMinusPress) && (partHit != kArrowPlusPress) &&
  3328.         (partHit != kPageMinusPress) && (partHit != kPagePlusPress))
  3329.         return AGATrackingIndicator::TrackPart(mouseLocation, partHit);
  3330.  
  3331.     Boolean    wasIn = FALSE;
  3332.     Boolean    isIn = TRUE;
  3333.     Boolean    isButtonDown = TRUE;    // ensure at least one time through
  3334.     Point    newMouseLocation;
  3335.     UInt32    accelerationDelay = 18;    // will divide by 2 each time
  3336.     
  3337.     while (isButtonDown)
  3338.         {
  3339.         if (isIn)
  3340.             this->TrackDelta(partHit);
  3341.  
  3342.         ::GetMouse(&newMouseLocation);    // gives local coordinates
  3343.         
  3344.         isIn = (this->TrackTestPart(newMouseLocation) == partHit);
  3345.         
  3346.         if (isIn != wasIn)
  3347.             this->DrawArrow(partHit, isIn);
  3348.         
  3349.         wasIn = isIn;
  3350.  
  3351.         if (isButtonDown && (accelerationDelay != 0))
  3352.             {
  3353.             DelayFutureWhileStillDown(accelerationDelay);
  3354.             accelerationDelay = accelerationDelay >> 1;    // divide by 2
  3355.             }
  3356.  
  3357.         isButtonDown = ::StillDown();
  3358.         }
  3359.     
  3360.     if (isIn)    // if finished IN, restore normal appearance
  3361.         this->DrawArrow(partHit, kNotPressed);
  3362.     
  3363.     return TRUE;
  3364.     }
  3365.  
  3366. SInt32 AGAScrollBar::TrackTestPart(Point mouseLocation)
  3367.     {
  3368.     // Return the part value that the specified mouse
  3369.     // position would hit.
  3370.  
  3371.     Rect    arrowMinusRect = mBounds;
  3372.     Rect    arrowPlusRect = mBounds;
  3373.     Rect    pageMinusRect = mBounds;
  3374.     Rect    pagePlusRect = mBounds;
  3375.     Rect    indicatorRect;
  3376.     
  3377.     this->GetIndicatorBox(mValue, &indicatorRect);
  3378.     
  3379.     if (mIsHorizontal)
  3380.         {
  3381.         arrowPlusRect.left = arrowPlusRect.right - kArrowSize;
  3382.         arrowMinusRect.right = arrowMinusRect.left + kArrowSize;
  3383.         
  3384.         pageMinusRect.left = arrowMinusRect.right;
  3385.         pageMinusRect.right = indicatorRect.left;
  3386.         
  3387.         pagePlusRect.left = indicatorRect.right;
  3388.         pagePlusRect.right = arrowPlusRect.left;
  3389.         }
  3390.     else
  3391.         {
  3392.         arrowPlusRect.top = arrowPlusRect.bottom - kArrowSize;
  3393.         arrowMinusRect.bottom = arrowMinusRect.top + kArrowSize;
  3394.         
  3395.         pageMinusRect.top = arrowMinusRect.bottom;
  3396.         pageMinusRect.bottom = indicatorRect.top;
  3397.         
  3398.         pagePlusRect.top = indicatorRect.bottom;
  3399.         pagePlusRect.bottom = arrowPlusRect.top;
  3400.         }
  3401.     
  3402.     if (::PtInRect(mouseLocation, &arrowMinusRect))
  3403.         return kArrowMinusPress;
  3404.     else if (::PtInRect(mouseLocation, &arrowPlusRect))
  3405.         return kArrowPlusPress;
  3406.     else if (::PtInRect(mouseLocation, &pageMinusRect))
  3407.         return kPageMinusPress;
  3408.     else if (::PtInRect(mouseLocation, &pagePlusRect))
  3409.         return kPagePlusPress;
  3410.     else if (::PtInRect(mouseLocation, &indicatorRect))
  3411.         return kIndicatorPress;
  3412.     else
  3413.         return kNoTrackPress;
  3414.     }
  3415.  
  3416. Boolean AGAScrollBar::IsValidIndicatorTrackMouse(Point mouseLocation)
  3417.     {
  3418.     // Return true if the mouse is reasonably near
  3419.     // the track.
  3420.  
  3421.     Rect    okRect = mBounds;
  3422.     
  3423.     ::InsetRect(&okRect, -32, -32);    // slop for mouse tracking
  3424.  
  3425.     return ::PtInRect(mouseLocation, &okRect);
  3426.     }
  3427.  
  3428. SInt32 AGAScrollBar::GetValueFromMouseDelta(SInt32 originalValue, Point originalMouseLocation, Point newMouseLocation)
  3429.     {
  3430.     // Return the new indicator value based on the mouse delta
  3431.     // from the original mouse location and indicator value.
  3432.  
  3433.     SInt32    dontCare;
  3434.     SInt32    valueRange = mMaximum - mMinimum;
  3435.     SInt32    pixelRange = this->GetIndicatorPixelRange(&dontCare);
  3436.     SInt32    pixelDelta;
  3437.     float    pixelFraction;
  3438.     
  3439.     if (mIsHorizontal)
  3440.         pixelDelta = newMouseLocation.h - originalMouseLocation.h;
  3441.     else
  3442.         pixelDelta = newMouseLocation.v - originalMouseLocation.v;
  3443.  
  3444.     pixelFraction = ((float) pixelDelta) / (float) pixelRange;
  3445.     
  3446.     float delta = pixelFraction * ((float) valueRange);
  3447.     delta += (float) 0.5;    // round to nearest integer, don't just truncate fraction
  3448.     
  3449.     return originalValue + delta;
  3450.     }
  3451.  
  3452. void AGAScrollBar::DrawIndicatorTrack()
  3453.     {
  3454.     CleansePen();
  3455.  
  3456.     // Draw the empty scroll bar track.
  3457.  
  3458.     GDIterator    iter;
  3459.     Boolean        deep;
  3460.  
  3461.     Boolean    enabled = mEnabled && (mMaximum > mMinimum);
  3462.  
  3463.     while (iter.More(deep))
  3464.         {
  3465.         if (deep)
  3466.             {
  3467.             Rect    r = mBounds;
  3468.  
  3469.             if (mActive)
  3470.                 ::RGBForeColor(&gAGARamp[rB]);
  3471.             else
  3472.                 ::RGBForeColor(&gAGARamp[r10]);
  3473.  
  3474.             ::FrameRect(&r);
  3475.             
  3476.             if (mIsHorizontal)
  3477.                 ::InsetRect(&r, kArrowSize - 1, 0);
  3478.             else
  3479.                 ::InsetRect(&r, 0, kArrowSize - 1);
  3480.             
  3481.             if ((! mActive) || (! enabled))
  3482.                 {
  3483.                 ::RGBForeColor(&gAGARamp[r1]);
  3484.                 ::InsetRect(&r, 1, 1);
  3485.                 ::PaintRect(&r);
  3486.                 ::InsetRect(&r, -1, -1);
  3487.                 
  3488.                 if (mActive)
  3489.                     ::RGBForeColor(&gAGARamp[r8]);
  3490.                 
  3491.                 if (mIsHorizontal)
  3492.                     {
  3493.                     ::MoveTo(r.left, r.top + 1);
  3494.                     ::LineTo(r.left, r.bottom - 2);
  3495.                     ::MoveTo(r.right - 1, r.top + 1);
  3496.                     ::LineTo(r.right - 1, r.bottom - 2);
  3497.                     }
  3498.                 else
  3499.                     {
  3500.                     ::MoveTo(r.left + 1, r.top);
  3501.                     ::LineTo(r.right - 2, r.top);
  3502.                     ::MoveTo(r.left + 1, r.bottom - 1);
  3503.                     ::LineTo(r.right - 2, r.bottom - 1);
  3504.                     }
  3505.                 }
  3506.             else    // enabled
  3507.                 {
  3508.                 ::RGBForeColor(&gAGARamp[r5]);
  3509.                 ::InsetRect(&r, 1, 1);
  3510.                 ::PaintRect(&r);
  3511.                 ::InsetRect(&r, -1, -1);
  3512.                 
  3513.                 ::RGBForeColor(&gAGARamp[rB]);
  3514.                 
  3515.                 if (mIsHorizontal)
  3516.                     {
  3517.                     ::MoveTo(r.left, r.top + 1);
  3518.                     ::LineTo(r.left, r.bottom - 2);
  3519.                     ::MoveTo(r.right - 1, r.top + 1);
  3520.                     ::LineTo(r.right - 1, r.bottom - 2);
  3521.                     
  3522.                     // Draw the shadowing.
  3523.  
  3524.                     ::RGBForeColor(&gAGARamp[r8]);
  3525.                     ::MoveTo(r.left + 1, r.bottom - 3);
  3526.                     ::LineTo(r.left + 1, r.top + 1);
  3527.                     ::LineTo(r.right - 2, r.top + 1);
  3528.  
  3529.                     ::RGBForeColor(&gAGARamp[r7]);
  3530.                     ::MoveTo(r.left + 2, r.bottom - 4);
  3531.                     ::LineTo(r.left + 2, r.top + 2);
  3532.                     ::LineTo(r.right - 3, r.top + 2);
  3533.  
  3534.                     ::RGBForeColor(&gAGARamp[r3]);
  3535.                     ::MoveTo(r.left + 2, r.bottom - 2);
  3536.                     ::LineTo(r.right - 2, r.bottom - 2);
  3537.  
  3538.                     ::RGBForeColor(&gAGARamp[r4]);
  3539.                     ::MoveTo(r.left + 3, r.bottom - 3);
  3540.                     ::LineTo(r.right - 2, r.bottom - 3);
  3541.                     }
  3542.                 else
  3543.                     {
  3544.                     ::MoveTo(r.left + 1, r.top);
  3545.                     ::LineTo(r.right - 2, r.top);
  3546.                     ::MoveTo(r.left + 1, r.bottom - 1);
  3547.                     ::LineTo(r.right - 2, r.bottom - 1);
  3548.                     
  3549.                     // Draw the shadowing.
  3550.  
  3551.                     ::RGBForeColor(&gAGARamp[r8]);
  3552.                     ::MoveTo(r.left + 1, r.bottom - 2);
  3553.                     ::LineTo(r.left + 1, r.top + 1);
  3554.                     ::LineTo(r.right - 3, r.top + 1);
  3555.  
  3556.                     ::RGBForeColor(&gAGARamp[r7]);
  3557.                     ::MoveTo(r.left + 2, r.bottom - 2);
  3558.                     ::LineTo(r.left + 2, r.top + 2);
  3559.                     ::LineTo(r.right - 4, r.top + 2);
  3560.  
  3561.                     ::RGBForeColor(&gAGARamp[r3]);
  3562.                     ::MoveTo(r.right - 2, r.top + 2);
  3563.                     ::LineTo(r.right - 2, r.bottom - 2);
  3564.  
  3565.                     ::RGBForeColor(&gAGARamp[r4]);
  3566.                     ::MoveTo(r.right - 3, r.top + 3);
  3567.                     ::LineTo(r.right - 3, r.bottom - 2);
  3568.                     }
  3569.                 }
  3570.             }
  3571.         else    // 1-bit
  3572.             {
  3573.             Rect    r = mBounds;
  3574.  
  3575.             ::InsetRect(&r, 1, 1);
  3576.             ::RGBForeColor(&gAGARamp[rW]);
  3577.             ::PaintRect(&r);
  3578.             ::InsetRect(&r, -1, -1);
  3579.  
  3580.             ::RGBForeColor(&gAGARamp[rB]);
  3581.             ::FrameRect(&mBounds);
  3582.  
  3583.             if (enabled && mActive)
  3584.                 {
  3585.                 if (mIsHorizontal)
  3586.                     {
  3587.                     ::InsetRect(&r, kArrowSize - 1, 0);
  3588.                     ::MoveTo(r.left, r.top + 1);
  3589.                     ::LineTo(r.left, r.bottom - 2);
  3590.                     ::MoveTo(r.right - 1, r.top + 1);
  3591.                     ::LineTo(r.right - 1, r.bottom - 2);
  3592.                     }
  3593.                 else
  3594.                     {
  3595.                     ::InsetRect(&r, 0, kArrowSize - 1);
  3596.                     ::MoveTo(r.left + 1, r.top);
  3597.                     ::LineTo(r.right - 2, r.top);
  3598.                     ::MoveTo(r.left + 1, r.bottom - 1);
  3599.                     ::LineTo(r.right - 2, r.bottom - 1);
  3600.                     }
  3601.                 }
  3602.             }
  3603.         }
  3604.  
  3605.     CleansePen();
  3606.     }
  3607.  
  3608. void AGAScrollBar::DrawTrackEnds()
  3609.     {
  3610.     CleansePen();
  3611.  
  3612.     // Draw the scroll arrows.
  3613.  
  3614.     this->DrawArrow(kArrowMinusPress, kNotPressed);
  3615.     this->DrawArrow(kArrowPlusPress, kNotPressed);
  3616.  
  3617.     CleansePen();
  3618.     }
  3619.  
  3620. void AGAScrollBar::DrawIndicator()
  3621.     {
  3622.     CleansePen();
  3623.  
  3624.     // Draw the thumb indicator.
  3625.  
  3626.     GDIterator    iter;
  3627.     Boolean        deep;
  3628.  
  3629.     while (iter.More(deep))
  3630.         {
  3631.         Boolean    enabled = mEnabled && (mMaximum > mMinimum);
  3632.  
  3633.         if ((! enabled) || (! mActive))
  3634.             return;
  3635.  
  3636.         enum { Fill, Light, TL, BR, Dark, kIndicatorColors };
  3637.  
  3638.         UInt8    colorIndexes[kIndicatorColors];
  3639.         Rect    r = mBounds;
  3640.         SInt32    startPt;
  3641.         SInt32    valuePt;
  3642.         SInt32    stopPt;
  3643.         Point    drawDirection;
  3644.         Point    moveDirection;
  3645.         SInt16    lineLength;
  3646.         
  3647.         if (deep)
  3648.             {
  3649.             if (mIsPressed)
  3650.                 {
  3651.                 colorIndexes[Fill] = r8;
  3652.                 colorIndexes[Light] = r3;
  3653.                 colorIndexes[TL] = r5;
  3654.                 colorIndexes[BR] = r10;
  3655.                 colorIndexes[Dark] = r12;
  3656.                 }
  3657.             else
  3658.                 {
  3659.                 colorIndexes[Fill] = r5;
  3660.                 colorIndexes[Light] = r1;
  3661.                 colorIndexes[TL] = r3;
  3662.                 colorIndexes[BR] = r8;
  3663.                 colorIndexes[Dark] = r10;
  3664.                 }
  3665.             }
  3666.         else
  3667.             {
  3668.             if (mIsPressed)
  3669.                 {
  3670.                 colorIndexes[Fill] = rB;
  3671.                 colorIndexes[Light] = rB;
  3672.                 colorIndexes[TL] = rW;
  3673.                 colorIndexes[BR] = rB;
  3674.                 colorIndexes[Dark] = rB;
  3675.                 }
  3676.             else
  3677.                 {
  3678.                 colorIndexes[Fill] = rW;
  3679.                 colorIndexes[Light] = rW;
  3680.                 colorIndexes[TL] = rB;
  3681.                 colorIndexes[BR] = rW;
  3682.                 colorIndexes[Dark] = rW;
  3683.                 }
  3684.             }
  3685.         
  3686.         this->GetIndicatorSpan(mValue, &startPt, &valuePt, &stopPt);
  3687.         this->GetIndicatorBox(mValue, &r);
  3688.         
  3689.         if (mIsHorizontal)
  3690.             {
  3691.             ::SetPt(&drawDirection, 0, 1);
  3692.             ::SetPt(&moveDirection, 1, 0);
  3693.             lineLength = r.bottom - r.top - 11;
  3694.             }
  3695.         else
  3696.             {
  3697.             ::SetPt(&drawDirection, 1, 0);
  3698.             ::SetPt(&moveDirection, 0, 1);
  3699.             lineLength = r.right - r.left - 11;
  3700.             }
  3701.  
  3702.         ::RGBForeColor(&gAGARamp[rB]);
  3703.         ::FrameRect(&r);
  3704.         
  3705.         ::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
  3706.         ::InsetRect(&r, 1, 1);
  3707.         ::PaintRect(&r);
  3708.         ::InsetRect(&r, -1, -1);
  3709.         
  3710.         if (deep)
  3711.             {
  3712.             ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  3713.             ::MoveTo(r.left + 1, r.bottom - 3);
  3714.             ::LineTo(r.left + 1, r.top + 2);
  3715.             ::Move(1, -1);
  3716.             ::LineTo(r.right - 3, r.top + 1);
  3717.             
  3718.             ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  3719.             ::MoveTo(r.right - 2, r.top + 2);
  3720.             ::LineTo(r.right - 2, r.bottom - 2);
  3721.             ::LineTo(r.left + 2, r.bottom - 2);
  3722.  
  3723.             ::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
  3724.             ::MoveTo(r.left + 1, r.top + 1);
  3725.             ::Line(0, 0);
  3726.             }
  3727.         
  3728.         ::MoveTo(r.left + 4 + (moveDirection.h * (((r.right - r.left) / 2) - 8)),
  3729.                 r.top + 4 + (moveDirection.v * (((r.bottom - r.top) / 2) - 8)));
  3730.  
  3731.         if (! deep)
  3732.             ::Move(moveDirection.h, moveDirection.v);
  3733.  
  3734.         for (SInt32 i = 0; i < 4; i++)
  3735.             {
  3736.             ::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
  3737.             ::Line(0, 0);
  3738.             
  3739.             ::Move(drawDirection.h, drawDirection.v);
  3740.             ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  3741.             ::Line(drawDirection.h * lineLength, drawDirection.v * lineLength);
  3742.             
  3743.             ::Move(moveDirection.h, moveDirection.v);
  3744.             ::Move(drawDirection.h, drawDirection.v);
  3745.             ::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
  3746.             ::Line(- (drawDirection.h * (lineLength+1)), - (drawDirection.v * (lineLength+1)));
  3747.  
  3748.             ::Move(moveDirection.h, moveDirection.v);
  3749.             ::Move(- drawDirection.h, - drawDirection.v);
  3750.             }
  3751.         }
  3752.  
  3753.     CleansePen();
  3754.     }
  3755.  
  3756. void AGAScrollBar::RemoveIndicator(SInt32 newValue)
  3757.     {
  3758.     CleansePen();
  3759.  
  3760.     // Draw the track/background to remove the current
  3761.     // indicator.
  3762.  
  3763.     //
  3764.     // Set clipping so we only draw the track to
  3765.     // wipe out the old indicator, but not where
  3766.     // the new indicator will get drawn anyway.
  3767.     // This reduces flicker.
  3768.     //
  3769.  
  3770.     ::GetClip(mgSavedIndicatorClip);
  3771.  
  3772.     if (newValue != mValue)
  3773.         {
  3774.         Rect    oldIndicatorBox;
  3775.         Rect    newIndicatorBox;
  3776.  
  3777.         this->GetIndicatorBox(mValue, &oldIndicatorBox);
  3778.         this->GetIndicatorBox(newValue, &newIndicatorBox);
  3779.         
  3780.         ::RectRgn(mgOldIndicatorClip, &oldIndicatorBox);
  3781.         ::RectRgn(mgNewIndicatorClip, &newIndicatorBox);
  3782.         ::DiffRgn(mgOldIndicatorClip, mgNewIndicatorClip, mgOldIndicatorClip);
  3783.  
  3784.         ::SetClip(mgOldIndicatorClip);
  3785.         }
  3786.  
  3787.     this->DrawIndicatorTrack();
  3788.  
  3789.     ::SetClip(mgSavedIndicatorClip);
  3790.  
  3791.     CleansePen();
  3792.     }
  3793.  
  3794. void AGAScrollBar::DrawGhost()
  3795.     {
  3796.     CleansePen();
  3797.  
  3798.     // Draw the indicator as a ghost at the current mGhostValue
  3799.     // position.
  3800.  
  3801.     GDIterator    iter;
  3802.     Boolean        deep;
  3803.  
  3804.     while (iter.More(deep))
  3805.         {
  3806.         Rect    r = mBounds;
  3807.         SInt32    startPt;
  3808.         SInt32    valuePt;
  3809.         SInt32    stopPt;
  3810.         Point    drawDirection;
  3811.         Point    moveDirection;
  3812.         SInt16    lineLength;
  3813.         
  3814.         this->GetIndicatorSpan(mGhostValue, &startPt, &valuePt, &stopPt);
  3815.         this->GetIndicatorBox(mGhostValue, &r);
  3816.         
  3817.         if (deep)
  3818.             {
  3819.             if (mIsHorizontal)
  3820.                 {
  3821.                 ::SetPt(&drawDirection, 0, 1);
  3822.                 ::SetPt(&moveDirection, 1, 0);
  3823.                 lineLength = r.bottom - r.top - 11;
  3824.                 
  3825.                 ::RGBForeColor(&gAGARamp[r4]);
  3826.                 ::InsetRect(&r, 1, 3);
  3827.                 ::PaintRect(&r);
  3828.                 ::InsetRect(&r, -1, -3);
  3829.                 
  3830.                 ::RGBForeColor(&gAGARamp[r11]);
  3831.                 ::MoveTo(r.left, r.top + 1);
  3832.                 ::Line(0, 0);
  3833.                 ::MoveTo(r.right - 1, r.top + 1);
  3834.                 ::Line(0, 0);
  3835.                 
  3836.                 ::RGBForeColor(&gAGARamp[r10]);
  3837.                 ::MoveTo(r.left, r.top + 2);
  3838.                 ::Line(0, 0);
  3839.                 ::MoveTo(r.right - 1, r.top + 2);
  3840.                 ::Line(0, 0);
  3841.                 
  3842.                 ::RGBForeColor(&gAGARamp[r8]);
  3843.                 ::MoveTo(r.left, r.top + 3);
  3844.                 ::LineTo(r.left, r.bottom - 4);
  3845.                 ::MoveTo(r.right - 1, r.top + 3);
  3846.                 ::LineTo(r.right - 1, r.bottom - 4);
  3847.                 
  3848.                 ::RGBForeColor(&gAGARamp[r6]);
  3849.                 ::MoveTo(r.left, r.bottom - 3);
  3850.                 ::Line(0, 0);
  3851.                 ::MoveTo(r.right - 1, r.bottom - 3);
  3852.                 ::Line(0, 0);
  3853.                 
  3854.                 ::RGBForeColor(&gAGARamp[r4]);
  3855.                 ::MoveTo(r.left, r.bottom - 2);
  3856.                 ::Line(0, 0);
  3857.                 ::MoveTo(r.right - 1, r.bottom - 2);
  3858.                 ::Line(0, 0);
  3859.                 
  3860.                 ::RGBForeColor(&gAGARamp[r6]);
  3861.                 ::MoveTo(r.left + 1, r.top + 1);
  3862.                 ::LineTo(r.right - 2, r.top + 1);
  3863.                 
  3864.                 ::RGBForeColor(&gAGARamp[r5]);
  3865.                 ::MoveTo(r.left + 1, r.top + 2);
  3866.                 ::LineTo(r.right - 2, r.top + 2);
  3867.                 
  3868.                 ::RGBForeColor(&gAGARamp[r3]);
  3869.                 ::MoveTo(r.left + 1, r.bottom - 3);
  3870.                 ::LineTo(r.right - 2, r.bottom - 3);
  3871.                 
  3872.                 ::RGBForeColor(&gAGARamp[r2]);
  3873.                 ::MoveTo(r.left + 1, r.bottom - 2);
  3874.                 ::LineTo(r.right - 2, r.bottom - 2);
  3875.                 }
  3876.             else
  3877.                 {
  3878.                 ::SetPt(&drawDirection, 1, 0);
  3879.                 ::SetPt(&moveDirection, 0, 1);
  3880.                 lineLength = r.right - r.left - 11;
  3881.                 
  3882.                 ::RGBForeColor(&gAGARamp[r4]);
  3883.                 ::InsetRect(&r, 3, 1);
  3884.                 ::PaintRect(&r);
  3885.                 ::InsetRect(&r, -3, -1);
  3886.                 
  3887.                 ::RGBForeColor(&gAGARamp[r11]);
  3888.                 ::MoveTo(r.left + 1, r.top);
  3889.                 ::Line(0, 0);
  3890.                 ::MoveTo(r.left + 1, r.bottom - 1);
  3891.                 ::Line(0, 0);
  3892.                 
  3893.                 ::RGBForeColor(&gAGARamp[r10]);
  3894.                 ::MoveTo(r.left + 2, r.top);
  3895.                 ::Line(0, 0);
  3896.                 ::MoveTo(r.left + 2, r.bottom - 1);
  3897.                 ::Line(0, 0);
  3898.                 
  3899.                 ::RGBForeColor(&gAGARamp[r8]);
  3900.                 ::MoveTo(r.left + 3, r.top);
  3901.                 ::LineTo(r.right - 4, r.top);
  3902.                 ::MoveTo(r.left + 3, r.bottom - 1);
  3903.                 ::LineTo(r.right - 4, r.bottom - 1);
  3904.                 
  3905.                 ::RGBForeColor(&gAGARamp[r6]);
  3906.                 ::MoveTo(r.right - 3, r.top);
  3907.                 ::Line(0, 0);
  3908.                 ::MoveTo(r.right - 3, r.bottom - 1);
  3909.                 ::Line(0, 0);
  3910.                 
  3911.                 ::RGBForeColor(&gAGARamp[r4]);
  3912.                 ::MoveTo(r.right - 2, r.top);
  3913.                 ::Line(0, 0);
  3914.                 ::MoveTo(r.right - 2, r.bottom - 1);
  3915.                 ::Line(0, 0);
  3916.                 
  3917.                 ::RGBForeColor(&gAGARamp[r6]);
  3918.                 ::MoveTo(r.left + 1, r.top + 1);
  3919.                 ::LineTo(r.left + 1, r.bottom - 2);
  3920.                 
  3921.                 ::RGBForeColor(&gAGARamp[r5]);
  3922.                 ::MoveTo(r.left + 2, r.top + 1);
  3923.                 ::LineTo(r.left + 2, r.bottom - 2);
  3924.                 
  3925.                 ::RGBForeColor(&gAGARamp[r3]);
  3926.                 ::MoveTo(r.right - 3, r.top + 1);
  3927.                 ::LineTo(r.right - 3, r.bottom - 2);
  3928.                 
  3929.                 ::RGBForeColor(&gAGARamp[r2]);
  3930.                 ::MoveTo(r.right - 2, r.top + 1);
  3931.                 ::LineTo(r.right - 2, r.bottom - 2);
  3932.                 }
  3933.  
  3934.             ::MoveTo(r.left + 4 + (moveDirection.h * (((r.right - r.left) / 2) - 8)),
  3935.                     r.top + 4 + (moveDirection.v * (((r.bottom - r.top) / 2) - 8)));
  3936.  
  3937.             for (SInt32 i = 0; i < 4; i++)
  3938.                 {
  3939.                 ::RGBForeColor(&gAGARamp[r2]);
  3940.                 ::Line(drawDirection.h * (lineLength+1), drawDirection.v * (lineLength+1));
  3941.                 
  3942.                 ::Move(moveDirection.h, moveDirection.v);
  3943.                 ::Move(drawDirection.h, drawDirection.v);
  3944.                 ::RGBForeColor(&gAGARamp[r6]);
  3945.                 ::Line(- (drawDirection.h * (lineLength+1)), - (drawDirection.v * (lineLength+1)));
  3946.  
  3947.                 ::Move(moveDirection.h, moveDirection.v);
  3948.                 ::Move(- drawDirection.h, - drawDirection.v);
  3949.                 }
  3950.             }
  3951.         else
  3952.             {
  3953.             ::RGBForeColor(&gAGARamp[rB]);
  3954.             ::FrameRect(&r);
  3955.             }
  3956.         }
  3957.  
  3958.     CleansePen();
  3959.     }
  3960.  
  3961. void AGAScrollBar::RemoveGhost(SInt32 newValue)
  3962.     {
  3963.     CleansePen();
  3964.  
  3965.     // Draw the track/background to remove the current
  3966.     // ghost indicator.
  3967.  
  3968.     Rect    r;
  3969.     RgnHandle    savedClip = ::NewRgn();
  3970.     
  3971.     ::GetClip(savedClip);
  3972.  
  3973.     this->GetIndicatorBox(mGhostValue, &r);
  3974.     ::ClipRect(&r);
  3975.     this->DrawIndicatorTrack();
  3976.     this->DrawIndicator();
  3977.     
  3978.     ::SetClip(savedClip);
  3979.  
  3980.     CleansePen();
  3981.     }
  3982.  
  3983. void AGAScrollBar::TrackDelta(SInt32 partHit)
  3984.     {
  3985.     // Change our value based on the delta amount
  3986.     // for the part that was hit. Do notification
  3987.     // of the value change.
  3988.  
  3989.     SInt32    oldValue = mValue;
  3990.     SInt32    newValue = mValue;
  3991.     
  3992.     switch (partHit)
  3993.         {
  3994.         case kPageMinusPress:
  3995.             newValue -= mPageStepSize;
  3996.             break;
  3997.         case kArrowMinusPress:
  3998.             newValue -= mSingleStepSize;
  3999.             break;
  4000.         case kArrowPlusPress:
  4001.             newValue += mSingleStepSize;
  4002.             break;
  4003.         case kPagePlusPress:
  4004.             newValue += mPageStepSize;
  4005.             break;
  4006.         }
  4007.     
  4008.     this->SetValue(newValue, kRedraw);
  4009.     
  4010.     if (mValue != oldValue)
  4011.         this->NotifyValue();
  4012.     }
  4013.  
  4014. void AGAScrollBar::DrawArrow(SInt32 arrowPart, Boolean pressed)
  4015.     {
  4016.     CleansePen();
  4017.  
  4018.     // Draw the specified arrow in the specified mode.
  4019.  
  4020.     Boolean    enabled = mEnabled && (mMaximum > mMinimum);
  4021.  
  4022.     if ((arrowPart != kArrowMinusPress) &&
  4023.         (arrowPart != kArrowPlusPress))
  4024.         return;
  4025.  
  4026.     enum { Fill, TL, BR, Arrow, kNumArrowColors };
  4027.  
  4028.     UInt8    colorIndexes[kNumArrowColors];
  4029.     Rect    r = mBounds;
  4030.     
  4031.     if (mIsHorizontal)
  4032.         {
  4033.         if (arrowPart == kArrowPlusPress)
  4034.             r.left = r.right - kArrowSize;
  4035.         else
  4036.             r.right = r.left + kArrowSize;
  4037.         }
  4038.     else
  4039.         {
  4040.         if (arrowPart == kArrowPlusPress)
  4041.             r.top = r.bottom - kArrowSize;
  4042.         else
  4043.             r.bottom = r.top + kArrowSize;
  4044.         }
  4045.     
  4046.     // Note: we don't draw the outer frame.
  4047.  
  4048.     GDIterator    iter;
  4049.     Boolean        deep;
  4050.  
  4051.     while (iter.More(deep))
  4052.         {
  4053.         if (deep)
  4054.             {
  4055.             if (! mActive)
  4056.                 {
  4057.                 colorIndexes[Fill] = r1;
  4058.                 colorIndexes[TL] = r1;
  4059.                 colorIndexes[BR] = r1;
  4060.                 colorIndexes[Arrow] = r1;
  4061.                 }
  4062.             else if (pressed)
  4063.                 {
  4064.                 colorIndexes[Fill] = r8;
  4065.                 colorIndexes[TL] = r10;
  4066.                 colorIndexes[BR] = r6;
  4067.                 colorIndexes[Arrow] = rB;
  4068.                 }
  4069.             else if (enabled)
  4070.                 {
  4071.                 colorIndexes[Fill] = r2;
  4072.                 colorIndexes[TL] = rW;
  4073.                 colorIndexes[BR] = r5;
  4074.                 colorIndexes[Arrow] = rB;
  4075.                 }
  4076.             else    // disabled
  4077.                 {
  4078.                 colorIndexes[Fill] = r2;
  4079.                 colorIndexes[TL] = rW;
  4080.                 colorIndexes[BR] = r4;
  4081.                 colorIndexes[Arrow] = r8;
  4082.                 }
  4083.             }
  4084.         else
  4085.             {
  4086.             if ((! mActive) || ! enabled)
  4087.                 {
  4088.                 colorIndexes[Fill] = rW;
  4089.                 colorIndexes[TL] = rW;
  4090.                 colorIndexes[BR] = rW;
  4091.                 colorIndexes[Arrow] = rW;
  4092.                 }
  4093.             else if (pressed)
  4094.                 {
  4095.                 colorIndexes[Fill] = rB;
  4096.                 colorIndexes[TL] = rB;
  4097.                 colorIndexes[BR] = rB;
  4098.                 colorIndexes[Arrow] = rW;
  4099.                 }
  4100.             else // unpressed + enabled
  4101.                 {
  4102.                 colorIndexes[Fill] = rW;
  4103.                 colorIndexes[TL] = rW;
  4104.                 colorIndexes[BR] = rW;
  4105.                 colorIndexes[Arrow] = rB;
  4106.                 }
  4107.             }
  4108.  
  4109.         ::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
  4110.         ::InsetRect(&r, 1, 1);
  4111.         ::PaintRect(&r);
  4112.         ::InsetRect(&r, -1, -1);
  4113.         
  4114.         ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  4115.         ::MoveTo(r.left + 1, r.bottom - 3);
  4116.         ::LineTo(r.left + 1, r.top + 1);
  4117.         ::LineTo(r.right - 3, r.top + 1);
  4118.  
  4119.         ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  4120.         ::MoveTo(r.right - 2, r.top + 2);
  4121.         ::LineTo(r.right - 2, r.bottom - 2);
  4122.         ::LineTo(r.left + 2, r.bottom - 2);
  4123.  
  4124.         ::RGBForeColor(&gAGARamp[colorIndexes[Arrow]]);
  4125.         SInt16    direction = (arrowPart == kArrowPlusPress) ? 1 : -1;
  4126.         SInt16    offset = (arrowPart == kArrowPlusPress) ? 6 : 9;
  4127.         
  4128.         if (mIsHorizontal)
  4129.             {
  4130.             ::MoveTo(r.left + offset, ((r.top + r.bottom) / 2) - 4);
  4131.             ::Line(0, 7);
  4132.             ::Move(direction, -6);
  4133.             ::Line(0, 5);
  4134.             ::Move(direction, -4);
  4135.             ::Line(0, 3);
  4136.             ::Move(direction, -2);
  4137.             ::Line(0, 1);
  4138.             }
  4139.         else
  4140.             {
  4141.             ::MoveTo(((r.left + r.right) / 2) - 4, r.top + offset);
  4142.             ::Line(7, 0);
  4143.             ::Move(-6, direction);
  4144.             ::Line(5, 0);
  4145.             ::Move(-4, direction);
  4146.             ::Line(3, 0);
  4147.             ::Move(-2, direction);
  4148.             ::Line(1, 0);
  4149.             }
  4150.         }
  4151.  
  4152.     CleansePen();
  4153.     }
  4154.  
  4155. void AGAScrollBar::GetIndicatorBox(SInt32 indicatorValue, Rect* indicatorBox)
  4156.     {
  4157.     // Return the bounds of the indicator box assuming that
  4158.     // it has specified indicator value.
  4159.  
  4160.     Rect    r = mBounds;
  4161.     SInt32    startPt;
  4162.     SInt32    valuePt;
  4163.     SInt32    stopPt;
  4164.  
  4165.     this->GetIndicatorSpan(indicatorValue, &startPt, &valuePt, &stopPt);
  4166.     
  4167.     if (mIsHorizontal)
  4168.         {
  4169.         r.left = startPt;
  4170.         r.right = stopPt;
  4171.         }
  4172.     else
  4173.         {
  4174.         r.top = startPt;
  4175.         r.bottom = stopPt;
  4176.         }
  4177.     
  4178.     *indicatorBox = r;
  4179.     }
  4180.  
  4181. SInt32 AGAScrollBar::GetIndicatorPixelRange(SInt32* proportionalIndicatorPixels)
  4182.     {
  4183.     // Return the pixel range that the center point of the indicator
  4184.     // can travel along the track, and also return the amount of
  4185.     // range reduction that is caused by proportional indicator growth.
  4186.     // Non-proportional indicators use the full track range, minus
  4187.     // the size of the indicator itself.
  4188.  
  4189.     SInt32    range;
  4190.     
  4191.     *proportionalIndicatorPixels = 0;
  4192.  
  4193.     if (mIsHorizontal)
  4194.         range = mBounds.right - mBounds.left - (2 * (kArrowSize + kIndicatorPixelInset)) + 1;
  4195.     else
  4196.         range = mBounds.bottom - mBounds.top - (2 * (kArrowSize + kIndicatorPixelInset)) + 1;
  4197.  
  4198.     if (mIsProportional)
  4199.         {
  4200.         SInt32    pagePixels;
  4201.         
  4202.         pagePixels =
  4203.             (range * (((float) mPageSize) / ((float) (mMaximum - mMinimum))));
  4204.         
  4205.         if (pagePixels > 0)
  4206.             {
  4207.             range -= pagePixels;
  4208.             *proportionalIndicatorPixels = pagePixels;
  4209.             }
  4210.         }
  4211.     
  4212.     return range;
  4213.     }
  4214.  
  4215. void AGAScrollBar::GetIndicatorPixelEnds(SInt32* startPt, SInt32* stopPt)
  4216.     {
  4217.     // Return the start and end pixel locations of the indicator
  4218.     // track traveled by the center point of the indicator.
  4219.  
  4220.     SInt32    dontCare;
  4221.     SInt32    range = this->GetIndicatorPixelRange(&dontCare);
  4222.  
  4223.     if (mIsHorizontal)
  4224.         {
  4225.         *startPt = ((mBounds.left + mBounds.right) / 2) - (range / 2) - 1;
  4226.         
  4227.         // Bump by 1 for odd-number width.
  4228.         if (((mBounds.right - mBounds.left) & 1) != 0)
  4229.             (*startPt)++;
  4230.         }
  4231.     else
  4232.         {
  4233.         *startPt = ((mBounds.top + mBounds.bottom) / 2) - (range / 2) - 1;
  4234.         
  4235.         // Bump by 1 for odd-number height.
  4236.         if (((mBounds.bottom - mBounds.top) & 1) != 0)
  4237.             (*startPt)++;
  4238.         }
  4239.  
  4240.     *stopPt = *startPt + range;    // avoid rounding of 1/2 pixel twice
  4241.     }
  4242.  
  4243. void AGAScrollBar::GetIndicatorSpan(SInt32 value, SInt32* startPt, SInt32* valuePt, SInt32* stopPt)
  4244.     {
  4245.     // Return the pixel locations of the indicator's ends and value.
  4246.  
  4247.     SInt32    proportionalIndicatorPixels;
  4248.     SInt32    trackStart;
  4249.     SInt32    trackStop;
  4250.     SInt32    trackRange = this->GetIndicatorPixelRange(&proportionalIndicatorPixels);
  4251.     
  4252.     this->GetIndicatorPixelEnds(&trackStart, &trackStop);
  4253.     
  4254.     *valuePt = trackStart +
  4255.         (trackRange * (((float) (value - mMinimum)) / ((float) (mMaximum - mMinimum))));
  4256.  
  4257.     *startPt = *valuePt - kIndicatorPixelInset - (proportionalIndicatorPixels / 2);
  4258.     *stopPt = *startPt + (2 * kIndicatorPixelInset) + proportionalIndicatorPixels + 1;
  4259.     }
  4260.  
  4261. //
  4262. // AGASlider ---------------------------------------------------------------
  4263. //
  4264. // This class implements a standard AGA slider, with the additional
  4265. // ability to perform live tracking and a proportional thumb.
  4266. //
  4267.  
  4268. // These regions are used momentarily while tracking the slider
  4269. // indicator to clip and optimize redrawing.
  4270. RgnHandle AGASlider::mgSavedIndicatorClip = ::NewRgn();
  4271. RgnHandle AGASlider::mgOldIndicatorClip = ::NewRgn();
  4272. RgnHandle AGASlider::mgNewIndicatorClip = ::NewRgn();
  4273.  
  4274. AGASlider::AGASlider(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, const AGATextStyle& textStyle, SInt16 labelsID)
  4275.     : AGATrackingIndicator(bounds, minimum, maximum, initialValue)
  4276.     {
  4277.     // Construct with default options.
  4278.     mPageSize = 0;
  4279.  
  4280.     mLabelStringHandles = NULL;
  4281.     mJustification = teFlushDefault;
  4282.     mTextStyle = textStyle;
  4283.  
  4284.     if (labelsID == 0)
  4285.         {
  4286.         mSliderKind = kRectSlider;
  4287.  
  4288.         mLiveTracking = TestGrayCouncilDefault(kAGALiveRSliders);
  4289.         mIsProportional = TestGrayCouncilDefault(kAGAProportionalRSliders);
  4290.         }
  4291.     else
  4292.         {
  4293.         mSliderKind = kPointerSlider;
  4294.         this->SetLabelsFromResource(labelsID);
  4295.  
  4296.         mLiveTracking = TestGrayCouncilDefault(kAGALivePSliders);
  4297.         mIsProportional = TestGrayCouncilDefault(kAGAProportionalPSliders);
  4298.         }
  4299.     }
  4300.  
  4301. AGASlider::AGASlider(Rect* bounds, SInt32 minimum, SInt32 maximum, SInt32 initialValue, const AGATextStyle& textStyle, SInt16 labelsID, SliderKind kind, Boolean liveTracking, Boolean proportional)
  4302.     : AGATrackingIndicator(bounds, minimum, maximum, initialValue, 1, liveTracking, proportional)
  4303.     {
  4304.     // Construct with specified options.
  4305.  
  4306.     mPageSize = 0;
  4307.  
  4308.     mLabelStringHandles = NULL;
  4309.     mJustification = teFlushDefault;
  4310.     mSliderKind = kind;
  4311.     mTextStyle = textStyle;
  4312.  
  4313.     this->SetLabelsFromResource(labelsID);
  4314.     }
  4315.  
  4316. AGASlider::~AGASlider()
  4317.     {
  4318.     // Destruct by releasing memory allocated for labels.
  4319.  
  4320.     this->DisposeLabels();
  4321.     }
  4322.  
  4323. void AGASlider::SetSliderKind(SliderKind kind)
  4324.     {
  4325.     // Set the slider kind (pointy or rectangular).
  4326.  
  4327.     mSliderKind = kind;
  4328.     }
  4329.  
  4330. void AGASlider::SetLabelsFromResource(SInt16 stringListResourceID)
  4331.     {
  4332.     // Build the slider labels from the specified 'STR#' resource.
  4333.     // A label slot is allocated for each string in the resource;
  4334.     // there will be a visual label tick for each of these strings.
  4335.     // If the current min/max range is smaller than the number of
  4336.     // labels (i.e., it's uninitialized), the min/max range will
  4337.     // be set to match the number of labels.
  4338.  
  4339.     this->DisposeLabels();
  4340.     
  4341.     if (stringListResourceID != 0)
  4342.         {
  4343.         SInt16**    stringListHandle = (SInt16**) ::GetResource('STR#', stringListResourceID);
  4344.         SInt16        numLabels = (stringListHandle == NULL) ? 0 : **stringListHandle;
  4345.         
  4346.         if (numLabels != 0)
  4347.             {
  4348.             mLabelStringHandles = ::NewHandleClear(numLabels * sizeof(StringHandle));
  4349.             
  4350.             for (SInt16 i = 0; i < numLabels; i++)
  4351.                 {
  4352.                 Str255            aLabel;
  4353.                 StringHandle    aStringHandle;
  4354.                 
  4355.                 ::GetIndString(aLabel, stringListResourceID, i+1);
  4356.                 aStringHandle = ::NewString(aLabel);
  4357.                 
  4358.                 ((StringHandle*)(*mLabelStringHandles))[i] = aStringHandle;
  4359.                 }
  4360.             }
  4361.     
  4362.         if ((mMaximum - mMinimum + 1) < numLabels)
  4363.             mMaximum = mMinimum + numLabels - 1;
  4364.         }
  4365.     }
  4366.  
  4367. void AGASlider::SetNumLabels(UInt32 numLabels)
  4368.     {
  4369.     // Allocate slots for the specified number of labels.
  4370.     // Any existing labels are thrown away.
  4371.  
  4372.     this->DisposeLabels();
  4373.     
  4374.     mLabelStringHandles = ::NewHandleClear(numLabels * sizeof(StringHandle));
  4375.  
  4376.     if ((mMaximum - mMinimum + 1) < numLabels)
  4377.         mMaximum = mMinimum + numLabels - 1;
  4378.     }
  4379.  
  4380. void AGASlider::SetLabel(UInt32 labelIndex, StringPtr itsLabel)
  4381.     {
  4382.     // Assign the specified string to the specified label slot.
  4383.  
  4384.     if (mLabelStringHandles != NULL)
  4385.         {
  4386.         UInt32    numLabels = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
  4387.         
  4388.         if (labelIndex < numLabels)
  4389.             ((StringHandle*)(*mLabelStringHandles))[labelIndex] = ::NewString(itsLabel);
  4390.         }
  4391.     }
  4392.  
  4393. void AGASlider::GetLabel(UInt32 labelIndex, StringPtr itsLabel)
  4394.     {
  4395.     // Return the label string of the specified label slot.
  4396.  
  4397.     itsLabel[0] = 0;
  4398.  
  4399.     if (mLabelStringHandles != NULL)
  4400.         {
  4401.         UInt32    numLabels = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
  4402.         
  4403.         if (labelIndex < numLabels)
  4404.             {
  4405.             Ptr    sourceStringPtr = (Ptr) *(((StringHandle*)(*mLabelStringHandles))[labelIndex]);
  4406.  
  4407.             ::BlockMoveData(sourceStringPtr, itsLabel, 1 + *sourceStringPtr);
  4408.             }
  4409.         }
  4410.     }
  4411.  
  4412. void AGASlider::SetLabelsStyle(const AGATextStyle& textStyle)
  4413.     {
  4414.     // Set the QuickDraw text style for the labels.
  4415.  
  4416.     mTextStyle = textStyle;
  4417.     }
  4418.  
  4419. void AGASlider::SetJustification(SInt32 justification)
  4420.     {
  4421.     // Set the justification of the slider. For vertical
  4422.     // sliders, default/left means the slider is on the
  4423.     // left and the labels are on the right; flush right
  4424.     // reverses this. For horizontal sliders, default/left
  4425.     // means the slider is above and the labels are below;
  4426.     // flush right reverses this.
  4427.     // In fact, for "teFlushDefault", the system script
  4428.     // direction is checked at runtime, so this is usually
  4429.     // what you should use. Use flush right or flush left
  4430.     // to force it one way or another.
  4431.  
  4432.     mJustification = justification;
  4433.     }
  4434.  
  4435. SInt32 AGASlider::TrackTestPart(Point mouseLocation)
  4436.     {
  4437.     // Return the indicator part value if the mouse location
  4438.     // would hit the indicator.
  4439.  
  4440.     Rect    indicatorRect;
  4441.     
  4442.     this->GetIndicatorBox(mValue, &indicatorRect);
  4443.     
  4444.     if (::PtInRect(mouseLocation, &indicatorRect))
  4445.         return kIndicatorPress;
  4446.     else
  4447.         return kNoTrackPress;
  4448.     }
  4449.  
  4450. Boolean AGASlider::IsValidIndicatorTrackMouse(Point mouseLocation)
  4451.     {
  4452.     // Return true if the mouse location is reasonably close
  4453.     // to the indicator track. This will depend on the
  4454.     // justification.
  4455.  
  4456.     Rect    okRect = mBounds;
  4457.     
  4458.     if (mIsHorizontal)
  4459.         {
  4460.         if (RuntimeJustify(mJustification) == teFlushLeft)
  4461.             okRect.bottom = okRect.top + kIndicatorWidth;
  4462.         else
  4463.             okRect.top = okRect.bottom - kIndicatorWidth;
  4464.         }
  4465.     else
  4466.         {
  4467.         if (RuntimeJustify(mJustification) == teFlushLeft)
  4468.             okRect.right = okRect.left + kIndicatorWidth;
  4469.         else
  4470.             okRect.left = okRect.right - kIndicatorWidth;
  4471.         }
  4472.     
  4473.     ::InsetRect(&okRect, -32, -32);    // slop for mouse tracking
  4474.  
  4475.     return ::PtInRect(mouseLocation, &okRect);
  4476.     }
  4477.  
  4478. SInt32 AGASlider::GetValueFromMouseDelta(SInt32 originalValue, Point originalMouseLocation, Point newMouseLocation)
  4479.     {
  4480.     // Return the new potential indicator value based on the mouse
  4481.     // delta from the original click location and the original value.
  4482.  
  4483.     SInt32    dontCare;
  4484.     SInt32    valueRange = mMaximum - mMinimum;
  4485.     SInt32    pixelRange = this->GetIndicatorPixelRange(&dontCare);
  4486.     SInt32    pixelDelta;
  4487.     float    pixelFraction;
  4488.     
  4489.     if (mIsHorizontal)
  4490.         pixelDelta = newMouseLocation.h - originalMouseLocation.h;
  4491.     else
  4492.         pixelDelta = newMouseLocation.v - originalMouseLocation.v;
  4493.  
  4494.     pixelFraction = ((float) pixelDelta) / (float) pixelRange;
  4495.     
  4496.     float delta = pixelFraction * ((float) valueRange);
  4497.     delta += (float) 0.5;    // round to nearest integer, don't just truncate fraction
  4498.     
  4499.     return originalValue + delta;
  4500.     }
  4501.  
  4502. void AGASlider::DrawBackground()
  4503.     {
  4504.     CleansePen();
  4505.  
  4506.     // Paint the background and labels.
  4507.  
  4508.     GDIterator    iter;
  4509.     Boolean        deep;
  4510.  
  4511.     while (iter.More(deep))
  4512.         {
  4513.         if (deep)
  4514.             ::RGBForeColor(&mBackgroundEraseColor);
  4515.         else
  4516.             ::RGBForeColor(&gAGARamp[rW]);
  4517.         }
  4518.  
  4519.     ::PaintRect(&mBounds);
  4520.     
  4521.     iter.Cleanup();    // Restore clipping since not yet destructed.
  4522.  
  4523.     this->DrawLabels();
  4524.  
  4525.     CleansePen();
  4526.     }
  4527.  
  4528. void AGASlider::DrawIndicatorTrack()
  4529.     {
  4530.     CleansePen();
  4531.  
  4532.     // Draw the empty slider track.
  4533.  
  4534.     GDIterator    iter;
  4535.     Boolean        deep;
  4536.  
  4537.     while (iter.More(deep))
  4538.         {
  4539.         if (deep)
  4540.             {
  4541.             Rect    trackFrame;
  4542.             
  4543.             this->GetTrackFrame(&trackFrame, kIncludeBackground);
  4544.  
  4545.             ::RGBForeColor(&mBackgroundEraseColor);
  4546.             ::PaintRect(&trackFrame);
  4547.             
  4548.             this->GetTrackFrame(&trackFrame, kTrackOnly);
  4549.  
  4550.             if (mEnabled)
  4551.                 ::RGBForeColor(&gAGARamp[rB]);
  4552.             else
  4553.                 ::RGBForeColor(&gAGARamp[r8]);
  4554.             
  4555.             ::InsetRect(&trackFrame, 1, 1);
  4556.             ::FrameRect(&trackFrame);
  4557.  
  4558.             if (mEnabled)
  4559.                 ::RGBForeColor(&gAGARamp[r5]);
  4560.             else
  4561.                 ::RGBForeColor(&gAGARamp[r4]);
  4562.             
  4563.             ::InsetRect(&trackFrame, 1, 1);
  4564.             ::PaintRect(&trackFrame);
  4565.             ::InsetRect(&trackFrame, -2, -2);
  4566.  
  4567.             ::MoveTo(trackFrame.left, trackFrame.bottom - 3);
  4568.             ::LineTo(trackFrame.left, trackFrame.top + 1);
  4569.             ::Line(1, 0);
  4570.             ::Line(0, -1);
  4571.             ::LineTo(trackFrame.right - 3, trackFrame.top);
  4572.             
  4573.             if (mIsHorizontal)
  4574.                 {
  4575.                 ::Move(1, 1);
  4576.                 ::Line(0, 0);
  4577.                 }
  4578.             
  4579.             ::RGBForeColor(&gAGARamp[rW]);
  4580.             ::MoveTo(trackFrame.left + 1, trackFrame.bottom - 2);
  4581.             ::Line(0, 0);
  4582.             ::Move(1, 1);
  4583.             ::LineTo(trackFrame.right - 2, trackFrame.bottom - 1);
  4584.             ::Line(0, -1);
  4585.             ::Line(1, 0);
  4586.             ::LineTo(trackFrame.right -  1, trackFrame.top + 2);
  4587.  
  4588.             if (! mIsHorizontal)
  4589.                 {
  4590.                 ::Move(-1, -1);
  4591.                 ::Line(0, 0);
  4592.                 }
  4593.             }
  4594.         else    // 1 -bit
  4595.             {
  4596.             Rect    trackFrame;
  4597.             
  4598.             this->GetTrackFrame(&trackFrame, kIncludeBackground);
  4599.  
  4600.             ::RGBForeColor(&gAGARamp[rW]);
  4601.             ::PaintRect(&trackFrame);
  4602.             
  4603.             this->GetTrackFrame(&trackFrame, kTrackOnly);
  4604.  
  4605.             ::RGBForeColor(&gAGARamp[rB]);
  4606.             
  4607.             if (! mEnabled)
  4608.                 ::PenPat(&qd.gray);
  4609.             
  4610.             ::InsetRect(&trackFrame, 1, 1);
  4611.             
  4612.             ::MoveTo(trackFrame.left + 1, trackFrame.top);
  4613.             ::LineTo(trackFrame.right - 2, trackFrame.top);
  4614.             ::Move(1, 1);
  4615.             ::LineTo(trackFrame.right - 1, trackFrame.bottom - 2);
  4616.             ::Move(-1, 1);
  4617.             ::LineTo(trackFrame.left + 1, trackFrame.bottom - 1);
  4618.             ::Move(-1, -1);
  4619.             ::LineTo(trackFrame.left, trackFrame.top + 1);
  4620.             
  4621.             if (! mEnabled)
  4622.                 ::PenPat(&qd.black);
  4623.             }
  4624.         }
  4625.  
  4626.     CleansePen();
  4627.     }
  4628.  
  4629. void AGASlider::DrawIndicator()
  4630.     {
  4631.     CleansePen();
  4632.  
  4633.     // Draw the slider indicator.
  4634.  
  4635.     Rect    indicatorRect;
  4636.     
  4637.     this->GetIndicatorBox(mValue, &indicatorRect);
  4638.  
  4639.     if (mSliderKind == kRectSlider)
  4640.         this->DrawRectIndicator(&indicatorRect, kNormalIndicator);
  4641.     else
  4642.         this->DrawPointerIndicator(&indicatorRect, kNormalIndicator);
  4643.  
  4644.     CleansePen();
  4645.     }
  4646.  
  4647. void AGASlider::DrawGhost()
  4648.     {
  4649.     CleansePen();
  4650.  
  4651.     // Draw the ghost slider indicator.
  4652.  
  4653.     Rect    indicatorRect;
  4654.     
  4655.     this->GetIndicatorBox(mGhostValue, &indicatorRect);
  4656.  
  4657.     if (mSliderKind == kRectSlider)
  4658.         this->DrawRectIndicator(&indicatorRect, kGhostIndicator);
  4659.     else
  4660.         this->DrawPointerIndicator(&indicatorRect, kGhostIndicator);
  4661.  
  4662.     CleansePen();
  4663.     }
  4664.  
  4665. void AGASlider::DrawLabels()
  4666.     {
  4667.     CleansePen();
  4668.  
  4669.     // Draw the slider labels and ticks.
  4670.  
  4671.     UInt32    numHandles = 0;
  4672.  
  4673.     if (mLabelStringHandles != NULL)
  4674.         numHandles = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
  4675.  
  4676.     if (numHandles < 2)    // Gotta at least label the ends, man!
  4677.         return;
  4678.     
  4679.     SInt16        tickRange;
  4680.     Point        tickOrigin;
  4681.     Point        drawDirection;
  4682.     Point        moveDirection;
  4683.     Rect        trackFrame;
  4684.     Boolean        flushLeft = (RuntimeJustify(mJustification) == teFlushLeft);
  4685.     FontInfo    fontInfo;
  4686.  
  4687.     mTextStyle.PrepareForDrawing();
  4688.     ::GetFontInfo(&fontInfo);
  4689.     
  4690.     this->GetTrackFrame(&trackFrame, kTrackOnly);
  4691.  
  4692.     if (mIsHorizontal)
  4693.         {
  4694.         tickRange = trackFrame.right - trackFrame.left - (2 * kLabelTickEndInset) - 1;
  4695.         drawDirection.h = 0;
  4696.         drawDirection.v = 1;
  4697.         moveDirection.h = 1;
  4698.         moveDirection.v = 0;
  4699.         tickOrigin.h = trackFrame.left + kLabelTickEndInset;
  4700.         
  4701.         if (flushLeft)
  4702.             tickOrigin.v = trackFrame.bottom + kLabelTickOffset;
  4703.         else
  4704.             tickOrigin.v = trackFrame.top - kLabelTickOffset - 2 - kLabelTickLength;
  4705.         }
  4706.     else
  4707.         {
  4708.         tickRange = trackFrame.bottom - trackFrame.top - (2 * kLabelTickEndInset) - 1;
  4709.         drawDirection.h = 1;
  4710.         drawDirection.v = 0;
  4711.         moveDirection.h = 0;
  4712.         moveDirection.v = 1;
  4713.         tickOrigin.v = trackFrame.top + kLabelTickEndInset;
  4714.         
  4715.         if (flushLeft)
  4716.             tickOrigin.h = trackFrame.right + kLabelTickOffset;
  4717.         else
  4718.             tickOrigin.h = trackFrame.left - kLabelTickOffset - 2 - kLabelTickLength;
  4719.         }
  4720.     
  4721.     GDIterator    iter;
  4722.     Boolean        deep;
  4723.  
  4724.     while (iter.More(deep))
  4725.         {
  4726.         for (UInt32 i = 0; i < numHandles; i++)
  4727.             {
  4728.             Point    tickLocation;
  4729.             float    fraction = ((float) i) / ((float) (numHandles - 1));
  4730.             
  4731.             tickLocation.h = tickOrigin.h + (moveDirection.h * tickRange * fraction);
  4732.             tickLocation.v = tickOrigin.v + (moveDirection.v * tickRange * fraction);
  4733.  
  4734.             ::MoveTo(tickLocation.h, tickLocation.v);
  4735.             
  4736.             ::RGBForeColor(&gAGARamp[rB]);
  4737.             
  4738.             if (! mEnabled)
  4739.                 {
  4740.                 if (deep)
  4741.                     ::RGBForeColor(&gAGARamp[r7]);
  4742.                 else
  4743.                     ::PenPat(&qd.gray);
  4744.                 }
  4745.  
  4746.             ::Line(drawDirection.h * (kLabelTickLength + 1), drawDirection.v * (kLabelTickLength + 1));
  4747.  
  4748.             ::PenNormal();
  4749.  
  4750.             if (deep)
  4751.                 {
  4752.                 // If disabled, we still draw in order to erase the 7/W
  4753.                 // shading pixels from prior enabled drawing.
  4754.  
  4755.                 if (mEnabled)
  4756.                     ::RGBForeColor(&gAGARamp[r7]);
  4757.                 else
  4758.                     ::RGBForeColor(&mBackgroundEraseColor);
  4759.  
  4760.                 ::Line(moveDirection.h, moveDirection.v);
  4761.                 ::Line( - (kLabelTickLength * drawDirection.h), - (kLabelTickLength * drawDirection.v));
  4762.                 
  4763.                 if (mEnabled)
  4764.                     ::RGBForeColor(&gAGARamp[rW]);
  4765.                 
  4766.                 ::Move(-1, -1);
  4767.                 ::Line(-moveDirection.h, -moveDirection.v);
  4768.                 ::Line(drawDirection.h * kLabelTickLength, drawDirection.v * kLabelTickLength);
  4769.                 }
  4770.  
  4771.             Str255    aLabel;
  4772.             Rect    labelBox;
  4773.             SInt16    labelHeight = fontInfo.ascent + fontInfo.descent;
  4774.             SInt16    labelWidth;
  4775.             SInt32    textJustification;
  4776.  
  4777.             this->GetLabel(i, aLabel);
  4778.             labelWidth = ::StringWidth(aLabel);
  4779.             
  4780.             if (mIsHorizontal)
  4781.                 {
  4782.                 textJustification = teCenter;
  4783.                 labelBox.left = tickLocation.h - (labelWidth / 2);
  4784.                 labelBox.right = labelBox.left + labelWidth;
  4785.  
  4786.                 if (flushLeft)
  4787.                     {
  4788.                     labelBox.top = tickLocation.v + 9;
  4789.                     labelBox.bottom = labelBox.top + labelHeight;
  4790.                     }
  4791.                 else
  4792.                     {
  4793.                     labelBox.bottom = tickLocation.v - 2;
  4794.                     labelBox.top = labelBox.bottom - labelHeight;
  4795.                     }
  4796.                 }
  4797.             else
  4798.                 {
  4799.                 textJustification = mJustification;
  4800.                 labelBox.top = tickLocation.v - (labelHeight / 2);
  4801.                 labelBox.bottom = labelBox.top + labelHeight;
  4802.  
  4803.                 if (flushLeft)
  4804.                     {
  4805.                     labelBox.left = tickLocation.h + 11;
  4806.                     labelBox.right = labelBox.left + labelWidth;
  4807.                     }
  4808.                 else
  4809.                     {
  4810.                     labelBox.right = tickLocation.h - 2;
  4811.                     labelBox.left = labelBox.right - labelWidth;
  4812.                     }
  4813.                 }
  4814.  
  4815.             //
  4816.             // To make view layout simpler, we assume that the labels may
  4817.             // extend outside the mBounds. So if this happens
  4818.             // we need to make sure we aren't being clipped out, but also
  4819.             // make sure we don't extend the unclipped area out to other
  4820.             // screens during device iteration.
  4821.             //
  4822.             
  4823.             RgnHandle    savedRegion = NULL;
  4824.  
  4825.             if ((labelBox.left < mBounds.left) ||
  4826.                 (labelBox.right > mBounds.right))
  4827.                 {
  4828.                 savedRegion = ::NewRgn();
  4829.                 ::GetClip(savedRegion);
  4830.                 ::InsetRect(&labelBox, -1, -1);
  4831.                 ::ClipRect(&labelBox);
  4832.                 ::InsetRect(&labelBox, 1, 1);
  4833.                 
  4834.                 iter.ClipFurtherToCurrentDevice();
  4835.                 }
  4836.  
  4837.             AGAStringOut(aLabel, &labelBox, kNoTruncation, textJustification, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle);
  4838.  
  4839.             if (savedRegion != NULL)
  4840.                 {
  4841.                 ::SetClip(savedRegion);
  4842.                 ::DisposeRgn(savedRegion);
  4843.                 }
  4844.             }
  4845.         }
  4846.  
  4847.     CleansePen();
  4848.     }
  4849.  
  4850. void AGASlider::DrawRectIndicator(Rect* indicatorRect, Boolean isGhost)
  4851.     {
  4852.     CleansePen();
  4853.  
  4854.     // Draw the rectangular slider indicator at the
  4855.     // specified location. The location will be sized
  4856.     // to account for a proportional indicator.
  4857.  
  4858.     enum { Frame, Fill, Corner, Light, TL, BR, Dark, Grip, BG, kNumIndicatorColors };
  4859.  
  4860.     UInt8    colorIndexes[kNumIndicatorColors];
  4861.     Rect    r = *indicatorRect;
  4862.     Point    drawDirection;
  4863.     Point    moveDirection;
  4864.     SInt16    lineLength;
  4865.  
  4866.     GDIterator    iter;
  4867.     Boolean        deep;
  4868.  
  4869.     while (iter.More(deep))
  4870.         {
  4871.         if (deep)
  4872.             {
  4873.             colorIndexes[BG] = r2;
  4874.  
  4875.             if (isGhost)
  4876.                 {
  4877.                 colorIndexes[Frame] = r7;
  4878.                 colorIndexes[Fill] = r2;
  4879.                 colorIndexes[Corner] = r1;
  4880.                 colorIndexes[Light] = rW;
  4881.                 colorIndexes[TL] = rW;
  4882.                 colorIndexes[BR] = r4;
  4883.                 colorIndexes[Dark] = r5;
  4884.                 colorIndexes[Grip] = rW;
  4885.                 }
  4886.             else if (! mEnabled)
  4887.                 {
  4888.                 colorIndexes[Frame] = r8;
  4889.                 colorIndexes[Fill] = r2;
  4890.                 colorIndexes[Corner] = rW;
  4891.                 colorIndexes[Light] = rW;
  4892.                 colorIndexes[TL] = r1;
  4893.                 colorIndexes[BR] = r4;
  4894.                 // n/a colorIndexes[Dark] = r9;
  4895.                 colorIndexes[Grip] = r1;
  4896.                 }
  4897.             else if (mIsPressed)
  4898.                 {
  4899.                 colorIndexes[Frame] = rB;
  4900.                 colorIndexes[Fill] = r8;
  4901.                 colorIndexes[Corner] = r3;
  4902.                 colorIndexes[Light] = r3;
  4903.                 colorIndexes[TL] = r5;
  4904.                 colorIndexes[BR] = r10;
  4905.                 colorIndexes[Dark] = r12;
  4906.                 colorIndexes[Grip] = r5;
  4907.                 }
  4908.             else // normal
  4909.                 {
  4910.                 colorIndexes[Frame] = rB;
  4911.                 colorIndexes[Fill] = r5;
  4912.                 colorIndexes[Corner] = r1;
  4913.                 colorIndexes[Light] = r1;
  4914.                 colorIndexes[TL] = r3;
  4915.                 colorIndexes[BR] = r8;
  4916.                 colorIndexes[Dark] = r10;
  4917.                 colorIndexes[Grip] = r3;
  4918.                 }
  4919.             }
  4920.         else    // 1-bit
  4921.             {
  4922.             colorIndexes[BG] = rW;
  4923.  
  4924.             if (isGhost)
  4925.                 {
  4926.                 colorIndexes[Frame] = rB;
  4927.                 colorIndexes[Fill] = rW;
  4928.                 colorIndexes[Corner] = rW;
  4929.                 colorIndexes[Light] = rW;
  4930.                 colorIndexes[TL] = rW;
  4931.                 colorIndexes[BR] = rW;
  4932.                 colorIndexes[Dark] = rW;
  4933.                 colorIndexes[Grip] = rB;
  4934.                 }
  4935.             else if (! mEnabled)
  4936.                 {
  4937.                 colorIndexes[Frame] = rB;
  4938.                 colorIndexes[Fill] = rW;
  4939.                 colorIndexes[Corner] = rW;
  4940.                 colorIndexes[Light] = rW;
  4941.                 colorIndexes[TL] = rW;
  4942.                 colorIndexes[BR] = rW;
  4943.                 colorIndexes[Dark] = rW;
  4944.                 colorIndexes[Grip] = rW;
  4945.                 }
  4946.             else if (mIsPressed)
  4947.                 {
  4948.                 colorIndexes[Frame] = rB;
  4949.                 colorIndexes[Fill] = rB;
  4950.                 colorIndexes[Corner] = rB;
  4951.                 colorIndexes[Light] = rB;
  4952.                 colorIndexes[TL] = rB;
  4953.                 colorIndexes[BR] = rB;
  4954.                 colorIndexes[Dark] = rB;
  4955.                 colorIndexes[Grip] = rW;
  4956.                 }
  4957.             else    // normal
  4958.                 {
  4959.                 colorIndexes[Frame] = rB;
  4960.                 colorIndexes[Fill] = rW;
  4961.                 colorIndexes[Corner] = rW;
  4962.                 colorIndexes[Light] = rW;
  4963.                 colorIndexes[TL] = rW;
  4964.                 colorIndexes[BR] = rW;
  4965.                 colorIndexes[Dark] = rW;
  4966.                 colorIndexes[Grip] = rB;
  4967.                 }
  4968.             }
  4969.         
  4970.         ::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
  4971.         ::FrameRect(&r);
  4972.         ::RGBForeColor(&gAGARamp[colorIndexes[BG]]);
  4973.         ::MoveTo(r.left, r.top);
  4974.         ::Line(0, 0);
  4975.         ::MoveTo(r.right - 1, r.top);
  4976.         ::Line(0, 0);
  4977.         ::MoveTo(r.right - 1, r.bottom - 1);
  4978.         ::Line(0, 0);
  4979.         ::MoveTo(r.left, r.bottom - 1);
  4980.         ::Line(0, 0);
  4981.         
  4982.         ::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
  4983.         ::InsetRect(&r, 1, 1);
  4984.         ::PaintRect(&r);
  4985.         ::InsetRect(&r, -1, -1);
  4986.         
  4987.         ::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
  4988.         ::MoveTo(r.left + 1, r.top + 1);
  4989.         ::Line(0, 0);
  4990.         
  4991.         ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  4992.         ::MoveTo(r.left + 1, r.bottom - 3);
  4993.         ::LineTo(r.left + 1, r.top + 2);
  4994.         ::Move(1, -1);
  4995.         ::LineTo(r.right - 3, r.top + 1);
  4996.         
  4997.         ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  4998.         ::Move(1, 1);
  4999.         ::LineTo(r.right - 2, r.bottom - 2);
  5000.         ::LineTo(r.left + 2, r.bottom - 2);
  5001.  
  5002.         if (mIsHorizontal)
  5003.             {
  5004.             ::SetPt(&drawDirection, 0, 1);
  5005.             ::SetPt(&moveDirection, 1, 0);
  5006.             lineLength = r.bottom - r.top - 10;
  5007.             }
  5008.         else
  5009.             {
  5010.             ::SetPt(&drawDirection, 1, 0);
  5011.             ::SetPt(&moveDirection, 0, 1);
  5012.             lineLength = r.right - r.left - 10;
  5013.             }
  5014.  
  5015.         if (mEnabled)
  5016.             {
  5017.             ::MoveTo(r.left + 3 + drawDirection.h + (moveDirection.h * (((r.right - r.left) / 2) - 6)),
  5018.                     r.top + 3 + drawDirection.v + (moveDirection.v * (((r.bottom - r.top) / 2) - 6)));
  5019.  
  5020.             if (! deep)
  5021.                 ::Move(moveDirection.h, moveDirection.v);
  5022.  
  5023.             for (SInt32 i = 0; i < 3; i++)
  5024.                 {
  5025.                 ::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
  5026.                 ::Line(drawDirection.h, drawDirection.v);
  5027.                 
  5028.                 ::RGBForeColor(&gAGARamp[colorIndexes[Grip]]);
  5029.                 ::Line(drawDirection.h * (lineLength-1), drawDirection.v * (lineLength-1));
  5030.                 
  5031.                 ::Move(moveDirection.h, moveDirection.v);
  5032.                 ::Move(drawDirection.h, drawDirection.v);
  5033.                 ::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
  5034.                 ::Line(- (drawDirection.h * lineLength), - (drawDirection.v * lineLength));
  5035.  
  5036.                 ::Move(moveDirection.h, moveDirection.v);
  5037.                 ::Move(- drawDirection.h, - drawDirection.v);
  5038.                 }
  5039.             }
  5040.         
  5041.         if (isGhost && deep)
  5042.             {
  5043.             // Draw the little see-thru track slides.
  5044.             // They run inverse draw direction from the grip lines.
  5045.             // To handle proportional indicators, we need to vary
  5046.             // the length of the track slides on the flat part.
  5047.             SInt32    wholeFlatLength;
  5048.             SInt32    firstFlatLength;
  5049.             SInt32    remainingFlatLength;
  5050.             
  5051.             if (mIsHorizontal)
  5052.                 wholeFlatLength = r.right - r.left - 10;
  5053.             else
  5054.                 wholeFlatLength = r.bottom - r.top - 10;
  5055.  
  5056.             firstFlatLength = wholeFlatLength / 2;
  5057.             remainingFlatLength = wholeFlatLength - firstFlatLength; // don't round down twice
  5058.  
  5059.             ::RGBForeColor(&gAGARamp[r11]);
  5060.             ::MoveTo(r.left + (drawDirection.h * 5), r.top + (drawDirection.v * 5));
  5061.             
  5062.             for (UInt32 i = 0; i < 2; i++)
  5063.                 {
  5064.                 ::Line(moveDirection.h, moveDirection.v);
  5065.                 ::RGBForeColor(&gAGARamp[r2]);
  5066.                 ::Line(moveDirection.h, moveDirection.v);
  5067.                 ::RGBForeColor(&gAGARamp[r5]);
  5068.                 ::Line(moveDirection.h * firstFlatLength, moveDirection.v * firstFlatLength);
  5069.                 ::RGBForeColor(&gAGARamp[r2]);
  5070.                 ::Line(moveDirection.h, moveDirection.v);
  5071.                 ::RGBForeColor(&gAGARamp[r9]);
  5072.                 ::Line(moveDirection.h, moveDirection.v);
  5073.                 ::RGBForeColor(&gAGARamp[r2]);
  5074.                 ::Line(moveDirection.h, moveDirection.v);
  5075.                 ::RGBForeColor(&gAGARamp[r9]);
  5076.                 ::Line(moveDirection.h, moveDirection.v);
  5077.                 ::RGBForeColor(&gAGARamp[r2]);
  5078.                 ::Line(moveDirection.h, moveDirection.v);
  5079.                 ::RGBForeColor(&gAGARamp[r9]);
  5080.                 ::Line(moveDirection.h, moveDirection.v);
  5081.                 ::RGBForeColor(&gAGARamp[r5]);
  5082.                 ::Line(moveDirection.h * remainingFlatLength, moveDirection.v * remainingFlatLength);
  5083.                 ::RGBForeColor(&gAGARamp[r7]);
  5084.                 ::Line(moveDirection.h, moveDirection.v);
  5085.                 ::RGBForeColor(&gAGARamp[r11]);
  5086.                 ::Line(0, 0);
  5087.                 
  5088.                 ::MoveTo(r.left + (drawDirection.h * 9), r.top + (drawDirection.v * 9));
  5089.                 }
  5090.             }
  5091.         }
  5092.  
  5093.     CleansePen();
  5094.     }
  5095.  
  5096. void AGASlider::DrawPointerIndicator(Rect* indicatorRect, Boolean isGhost)
  5097.     {
  5098.     CleansePen();
  5099.  
  5100.     // Draw the pointy slider indicator at the
  5101.     // specified location. The location will be sized
  5102.     // to account for a proportional indicator.
  5103.  
  5104.     enum { Frame, Fill, Corner, Light, TL, Grip, BR, Dark, kNumIndicatorColors };
  5105.  
  5106.     UInt8    colorIndexes[kNumIndicatorColors];
  5107.     Rect    r = *indicatorRect;
  5108.     Point    drawDirection;
  5109.     Point    moveDirection;
  5110.     SInt16    lineLength;
  5111.     SInt16    propExtra;    // extra pixels due to proportional indicator shape
  5112.  
  5113.     GDIterator    iter;
  5114.     Boolean        deep;
  5115.  
  5116.     while (iter.More(deep))
  5117.         {
  5118.         if (deep)
  5119.             {
  5120.             if (isGhost)
  5121.                 {
  5122.                 colorIndexes[Frame] = r7;
  5123.                 colorIndexes[Fill] = r2;
  5124.                 colorIndexes[Corner] = r1;
  5125.                 colorIndexes[Light] = rW;
  5126.                 colorIndexes[TL] = rW;
  5127.                 colorIndexes[Grip] = rW;
  5128.                 colorIndexes[BR] = r4;
  5129.                 colorIndexes[Dark] = r5;
  5130.                 }
  5131.             else if (! mEnabled)
  5132.                 {
  5133.                 colorIndexes[Frame] = r8;
  5134.                 colorIndexes[Fill] = r2;
  5135.                 colorIndexes[Corner] = rW;
  5136.                 colorIndexes[Light] = rW;
  5137.                 colorIndexes[TL] = r1;
  5138.                 colorIndexes[Grip] = r1;
  5139.                 colorIndexes[BR] = r4;
  5140.                 // n/a colorIndexes[Dark] = r9;
  5141.                 }
  5142.             else if (mIsPressed)
  5143.                 {
  5144.                 colorIndexes[Frame] = rB;
  5145.                 colorIndexes[Fill] = r8;
  5146.                 colorIndexes[Corner] = r3;
  5147.                 colorIndexes[Light] = r3;
  5148.                 colorIndexes[TL] = r5;
  5149.                 colorIndexes[Grip] = r5;
  5150.                 colorIndexes[BR] = r10;
  5151.                 colorIndexes[Dark] = r12;
  5152.                 }
  5153.             else // normal
  5154.                 {
  5155.                 colorIndexes[Frame] = rB;
  5156.                 colorIndexes[Fill] = r5;
  5157.                 colorIndexes[Corner] = r1;
  5158.                 colorIndexes[Light] = r1;
  5159.                 colorIndexes[TL] = r3;
  5160.                 colorIndexes[Grip] = r3;
  5161.                 colorIndexes[BR] = r8;
  5162.                 colorIndexes[Dark] = r10;
  5163.                 }
  5164.             }
  5165.         else    // 1-bit
  5166.             {
  5167.             if (isGhost)
  5168.                 {
  5169.                 colorIndexes[Frame] = rB;
  5170.                 colorIndexes[Fill] = rW;
  5171.                 colorIndexes[Corner] = rW;
  5172.                 colorIndexes[Light] = rW;
  5173.                 colorIndexes[TL] = rW;
  5174.                 colorIndexes[Grip] = rW;
  5175.                 colorIndexes[BR] = rW;
  5176.                 colorIndexes[Dark] = rW;
  5177.                 }
  5178.             else if (! mEnabled)
  5179.                 {
  5180.                 colorIndexes[Frame] = rB;
  5181.                 colorIndexes[Fill] = rW;
  5182.                 colorIndexes[Corner] = rW;
  5183.                 colorIndexes[Light] = rW;
  5184.                 colorIndexes[TL] = rW;
  5185.                 colorIndexes[Grip] = rW;
  5186.                 colorIndexes[BR] = rW;
  5187.                 colorIndexes[Dark] = rW;
  5188.                 }
  5189.             else if (mIsPressed)
  5190.                 {
  5191.                 colorIndexes[Frame] = rB;
  5192.                 colorIndexes[Fill] = rB;
  5193.                 colorIndexes[Corner] = rB;
  5194.                 colorIndexes[Light] = rB;
  5195.                 colorIndexes[TL] = rB;
  5196.                 colorIndexes[Grip] = rW;
  5197.                 colorIndexes[BR] = rB;
  5198.                 colorIndexes[Dark] = rB;
  5199.                 }
  5200.             else // normal
  5201.                 {
  5202.                 colorIndexes[Frame] = rB;
  5203.                 colorIndexes[Fill] = rW;
  5204.                 colorIndexes[Corner] = rW;
  5205.                 colorIndexes[Light] = rW;
  5206.                 colorIndexes[TL] = rW;
  5207.                 colorIndexes[Grip] = rB;
  5208.                 colorIndexes[BR] = rW;
  5209.                 colorIndexes[Dark] = rW;
  5210.                 }
  5211.             }
  5212.  
  5213.         if (mIsHorizontal)
  5214.             {
  5215.             ::SetPt(&drawDirection, 0, 1);
  5216.             ::SetPt(&moveDirection, 1, 0);
  5217.             lineLength = r.bottom - r.top - 11;
  5218.             propExtra = MaxSInt16(0, r.right - r.left - 15);
  5219.             }
  5220.         else
  5221.             {
  5222.             ::SetPt(&drawDirection, 1, 0);
  5223.             ::SetPt(&moveDirection, 0, 1);
  5224.             lineLength = r.right - r.left - 11;
  5225.             propExtra = MaxSInt16(0, r.bottom - r.top - 15);
  5226.             }
  5227.         
  5228.         PolyHandle    pointerPoly = ::OpenPoly();
  5229.         
  5230.         this->BuildPointerIndicator(indicatorRect);
  5231.         
  5232.         ::ClosePoly();
  5233.         
  5234.         ::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
  5235.         ::PaintPoly(pointerPoly);
  5236.         ::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
  5237.         ::FramePoly(pointerPoly);
  5238.         
  5239.         ::KillPoly(pointerPoly);
  5240.  
  5241.         if (mIsHorizontal)
  5242.             {
  5243.             if (RuntimeJustify(mJustification) == teFlushLeft)
  5244.                 {
  5245.                 ::MoveTo(r.left + 1, r.top + 1);
  5246.                 ::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
  5247.                 ::Line(0, 0);
  5248.                 ::MoveTo(r.right - 2, r.top + 2);
  5249.                 ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  5250.                 ::LineTo(r.right - 2, r.top + 9);
  5251.                 ::Line(-5, 5);
  5252.                 ::Line(-2 - propExtra, 0);
  5253.                 ::Line(-5, -5);
  5254.                 ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  5255.                 ::LineTo(r.left + 1, r.top + 2);
  5256.                 ::Line(1, -1);
  5257.                 ::LineTo(r.right - 3, r.top + 1);
  5258.                 }
  5259.             else
  5260.                 {
  5261.                 ::MoveTo(r.right - 6, r.top + 2);
  5262.                 ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  5263.                 ::Line(4, 4);
  5264.                 ::LineTo(r.right - 2, r.bottom - 2);
  5265.                 ::LineTo(r.left + 2, r.bottom - 2);
  5266.                 ::Move(-1, -1);
  5267.                 ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  5268.                 ::Line(0, -7);
  5269.                 ::Line(5, -5);
  5270.                 ::Line(1 + propExtra, 0);
  5271.                 ::MoveTo(r.left + 6, r.top + 1);
  5272.                 ::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
  5273.                 ::Line(0, 0);
  5274.                 ::Move(-5, 5);
  5275.                 ::Line(0, 0);
  5276.                 }
  5277.             }
  5278.         else
  5279.             {
  5280.             if (RuntimeJustify(mJustification) == teFlushLeft)
  5281.                 {
  5282.                 ::MoveTo(r.left + 1, r.top + 1);
  5283.                 ::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
  5284.                 ::Line(0, 0);
  5285.                 ::MoveTo(r.left + 1, r.bottom - 3);
  5286.                 ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  5287.                 ::LineTo(r.left + 1, r.top + 2);
  5288.                 ::Line(1, -1);
  5289.                 ::Line(7, 0);
  5290.                 ::Move(1, 1);
  5291.                 ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  5292.                 ::Line(4, 4);
  5293.                 ::Line(0, 2 + propExtra);
  5294.                 ::Line(-5, 5);
  5295.                 ::Line(-7, 0);
  5296.                 }
  5297.             else
  5298.                 {
  5299.                 ::MoveTo(r.left + 2, r.top + 9 + propExtra);
  5300.                 ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  5301.                 ::Line(4, 4);
  5302.                 ::LineTo(r.right - 2, r.bottom - 2);
  5303.                 ::LineTo(r.right - 2, r.top + 2);
  5304.                 ::Move(-1, -1);
  5305.                 ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  5306.                 ::Line(-7, 0);
  5307.                 ::Line(-5, 5);
  5308.                 ::Line(0, 1 + propExtra);
  5309.                 ::Move(0, - (1 + propExtra));
  5310.                 ::RGBForeColor(&gAGARamp[colorIndexes[Corner]]);
  5311.                 ::Line(0, 0);
  5312.                 ::Move(5, -5);
  5313.                 ::Line(0, 0);
  5314.                 }
  5315.             }
  5316.         
  5317.         if (mEnabled)
  5318.             {
  5319.             ::MoveTo(r.left + 3 + (moveDirection.h * (((r.right - r.left) / 2) - 6)),
  5320.                     r.top + 3 + (moveDirection.v * (((r.bottom - r.top) / 2) - 6)));
  5321.  
  5322.             if (RuntimeJustify(mJustification) == teFlushRight)
  5323.                 ::Move(2 * drawDirection.h, 2 * drawDirection.v);
  5324.  
  5325.             if (! deep)
  5326.                 ::Move(moveDirection.h, moveDirection.v);
  5327.  
  5328.             for (SInt32 i = 0; i < 3; i++)
  5329.                 {
  5330.                 ::RGBForeColor(&gAGARamp[colorIndexes[Light]]);
  5331.                 ::Line(drawDirection.h, drawDirection.v);
  5332.                 
  5333.                 ::RGBForeColor(&gAGARamp[colorIndexes[Grip]]);
  5334.                 ::Line(drawDirection.h * (lineLength-1), drawDirection.v * (lineLength-1));
  5335.                 
  5336.                 ::Move(moveDirection.h, moveDirection.v);
  5337.                 ::Move(drawDirection.h, drawDirection.v);
  5338.                 ::RGBForeColor(&gAGARamp[colorIndexes[Dark]]);
  5339.                 ::Line(- (drawDirection.h * lineLength), - (drawDirection.v * lineLength));
  5340.  
  5341.                 ::Move(moveDirection.h, moveDirection.v);
  5342.                 ::Move(- drawDirection.h, - drawDirection.v);
  5343.                 }
  5344.             }
  5345.         
  5346.         if (isGhost && deep)
  5347.             {
  5348.             // Draw the little see-thru track slides.
  5349.             // They run inverse draw direction from the grip lines.
  5350.             // To handle proportional indicators, we need to vary
  5351.             // the length of the track slides on the flat part.
  5352.             SInt32    wholeFlatLength;
  5353.             SInt32    firstFlatLength;
  5354.             SInt32    remainingFlatLength;
  5355.             
  5356.             if (mIsHorizontal)
  5357.                 wholeFlatLength = r.right - r.left - 10;
  5358.             else
  5359.                 wholeFlatLength = r.bottom - r.top - 10;
  5360.  
  5361.             firstFlatLength = wholeFlatLength / 2;
  5362.             remainingFlatLength = wholeFlatLength - firstFlatLength; // don't round down twice
  5363.  
  5364.             ::RGBForeColor(&gAGARamp[r11]);
  5365.             ::MoveTo(r.left + (drawDirection.h * 4), r.top + (drawDirection.v * 4));
  5366.             
  5367.             for (UInt32 i = 0; i < 2; i++)
  5368.                 {
  5369.                 if (RuntimeJustify(mJustification) == teFlushRight)
  5370.                     ::Move(3 * drawDirection.h, 3 * drawDirection.v);
  5371.  
  5372.                 ::Line(moveDirection.h, moveDirection.v);
  5373.                 ::RGBForeColor(&gAGARamp[r2]);
  5374.                 ::Line(moveDirection.h, moveDirection.v);
  5375.                 ::RGBForeColor(&gAGARamp[r5]);
  5376.                 ::Line(moveDirection.h * firstFlatLength, moveDirection.v * firstFlatLength);
  5377.                 ::RGBForeColor(&gAGARamp[r2]);
  5378.                 ::Line(moveDirection.h, moveDirection.v);
  5379.                 ::RGBForeColor(&gAGARamp[r9]);
  5380.                 ::Line(moveDirection.h, moveDirection.v);
  5381.                 ::RGBForeColor(&gAGARamp[r2]);
  5382.                 ::Line(moveDirection.h, moveDirection.v);
  5383.                 ::RGBForeColor(&gAGARamp[r9]);
  5384.                 ::Line(moveDirection.h, moveDirection.v);
  5385.                 ::RGBForeColor(&gAGARamp[r2]);
  5386.                 ::Line(moveDirection.h, moveDirection.v);
  5387.                 ::RGBForeColor(&gAGARamp[r9]);
  5388.                 ::Line(moveDirection.h, moveDirection.v);
  5389.                 ::RGBForeColor(&gAGARamp[r5]);
  5390.                 ::Line(moveDirection.h * remainingFlatLength, moveDirection.v * remainingFlatLength);
  5391.                 ::RGBForeColor(&gAGARamp[r7]);
  5392.                 ::Line(moveDirection.h, moveDirection.v);
  5393.                 ::RGBForeColor(&gAGARamp[r11]);
  5394.                 ::Line(0, 0);
  5395.                 
  5396.                 ::MoveTo(r.left + (drawDirection.h * 8), r.top + (drawDirection.v * 8));
  5397.                 }
  5398.             }
  5399.         }
  5400.  
  5401.     CleansePen();
  5402.     }
  5403.  
  5404. void AGASlider::BuildPointerIndicator(Rect* indicatorRect)
  5405.     {
  5406.     // Perform the QuickDraw framing commands to build the
  5407.     // pointy indicator. This function is called while wrapped
  5408.     // in polygon or region building calls. The caller will
  5409.     // use the resulting polygon or region to frame, fill,
  5410.     // or clip.
  5411.  
  5412.     Rect    r = *indicatorRect;
  5413.     SInt16    propExtra;
  5414.  
  5415.     if (mIsHorizontal)
  5416.         {
  5417.         propExtra = MaxSInt16(0, r.right - r.left - 15);
  5418.  
  5419.         if (RuntimeJustify(mJustification) == teFlushLeft)
  5420.             {
  5421.             ::MoveTo(r.right - 1, r.top + 1);
  5422.             ::LineTo(r.right - 1, r.bottom - 7);
  5423.             ::Line(-6, 6);
  5424.             ::Line(-2 - propExtra, 0);
  5425.             ::Line(-6, -6);
  5426.             ::LineTo(r.left, r.top + 1);
  5427.             ::Line(1, -1);
  5428.             ::LineTo(r.right - 2, r.top);
  5429.             ::Line(1, 1);
  5430.             }
  5431.         else
  5432.             {
  5433.             ::MoveTo(r.left, r.bottom - 2);
  5434.             ::LineTo(r.left, r.top + 6);
  5435.             ::Line(6, -6);
  5436.             ::Line(2 + propExtra, 0);
  5437.             ::Line(6, 6);
  5438.             ::LineTo(r.right - 1, r.bottom - 2);
  5439.             ::Line(-1, 1);
  5440.             ::LineTo(r.left + 1, r.bottom - 1);
  5441.             ::Line(-1, -1);
  5442.             }
  5443.         }
  5444.     else
  5445.         {
  5446.         propExtra = MaxSInt16(0, r.bottom - r.top - 15);
  5447.  
  5448.         if (RuntimeJustify(mJustification) == teFlushLeft)
  5449.             {
  5450.             ::MoveTo(r.left + 1, r.top);
  5451.             ::LineTo(r.right - 7, r.top);
  5452.             ::Line(6, 6);
  5453.             ::Line(0, 2 + propExtra);
  5454.             ::Line(-6, 6);
  5455.             ::LineTo(r.left + 1, r.bottom - 1);
  5456.             ::Line(-1, -1);
  5457.             ::LineTo(r.left, r.top + 1);
  5458.             ::Line(1, -1);
  5459.             }
  5460.         else
  5461.             {
  5462.             ::MoveTo(r.right - 2, r.bottom - 1);
  5463.             ::LineTo(r.left + 6, r.bottom - 1);
  5464.             ::Line(-6, -6);
  5465.             ::Line(0, -2 - propExtra);
  5466.             ::Line(6, -6);
  5467.             ::LineTo(r.right - 2, r.top);
  5468.             ::Line(1, 1);
  5469.             ::LineTo(r.right - 1, r.bottom - 2);
  5470.             ::Line(-1, 1);
  5471.             }
  5472.         }
  5473.     }
  5474.  
  5475. void AGASlider::RemoveIndicator(SInt32 newValue)
  5476.     {
  5477.     // Draw the background to remove the indicator
  5478.     // at the specified value.
  5479.  
  5480.     //
  5481.     // Set clipping so we only draw the track to
  5482.     // wipe out the old indicator, but not where
  5483.     // the new indicator will get drawn anyway.
  5484.     // This reduces flicker. Polygon geometry makes
  5485.     // tweaking necessary and still imperfect.
  5486.     //
  5487.  
  5488.     ::GetClip(mgSavedIndicatorClip);
  5489.  
  5490.     if (newValue != mValue)
  5491.         {
  5492.         Rect    oldIndicatorBox;
  5493.         Rect    newIndicatorBox;
  5494.  
  5495.         this->GetIndicatorBox(mValue, &oldIndicatorBox);
  5496.         this->GetIndicatorBox(newValue, &newIndicatorBox);
  5497.         
  5498.         if (mSliderKind == kRectSlider)
  5499.             {
  5500.             ::RectRgn(mgOldIndicatorClip, &oldIndicatorBox);
  5501.             ::RectRgn(mgNewIndicatorClip, &newIndicatorBox);
  5502.             }
  5503.         else
  5504.             {
  5505.             //
  5506.             // For optimal clipping, because of polygon and
  5507.             // region geometry, we have to tweak the regions
  5508.             // a little bit.
  5509.             //
  5510.             
  5511.             RgnHandle    tempRegion = ::NewRgn();
  5512.  
  5513.             ::OpenRgn();
  5514.             this->BuildPointerIndicator(&oldIndicatorBox);
  5515.             ::CloseRgn(mgOldIndicatorClip);
  5516.             ::CopyRgn(mgOldIndicatorClip, tempRegion);
  5517.             ::OffsetRgn(tempRegion, 1, 1);
  5518.             ::InsetRgn(tempRegion, -1, -1);
  5519.             ::UnionRgn(mgOldIndicatorClip, tempRegion, mgOldIndicatorClip);
  5520.  
  5521.             ::OpenRgn();
  5522.             this->BuildPointerIndicator(&newIndicatorBox);
  5523.             ::CloseRgn(mgNewIndicatorClip);
  5524.             ::CopyRgn(mgNewIndicatorClip, tempRegion);
  5525.             ::UnionRgn(mgNewIndicatorClip, tempRegion, mgNewIndicatorClip);
  5526.             
  5527.             ::DisposeRgn(tempRegion);
  5528.             }
  5529.  
  5530.         ::DiffRgn(mgOldIndicatorClip, mgNewIndicatorClip, mgOldIndicatorClip);
  5531.  
  5532.         ::SetClip(mgOldIndicatorClip);
  5533.         }
  5534.  
  5535.     this->DrawIndicatorTrack();
  5536.  
  5537.     ::SetClip(mgSavedIndicatorClip);
  5538.     }
  5539.  
  5540. void AGASlider::RemoveGhost(SInt32 newValue)
  5541.     {
  5542.     // Draw the background necessary to remove the
  5543.     // ghost indicator while not removing the solid
  5544.     // value indicator.
  5545.  
  5546.     Rect    r;
  5547.     RgnHandle    savedClip = ::NewRgn();
  5548.     
  5549.     ::GetClip(savedClip);
  5550.  
  5551.     this->GetIndicatorBox(mGhostValue, &r);
  5552.     ::ClipRect(&r);
  5553.     this->DrawIndicatorTrack();
  5554.     this->DrawIndicator();
  5555.     
  5556.     ::SetClip(savedClip);
  5557.     ::DisposeRgn(savedClip);
  5558.     }
  5559.  
  5560. void AGASlider::GetTrackFrame(Rect* trackFrame, Boolean includeBackground)
  5561.     {
  5562.     // Return the rectangle that bounds just the indicator
  5563.     // track, including shading pixels but not the area covered
  5564.     // by the indicator itself.
  5565.  
  5566.     Boolean    leftJustify = (RuntimeJustify(mJustification) == teFlushLeft);
  5567.  
  5568.     *trackFrame = mBounds;
  5569.     
  5570.     if (mIsHorizontal)
  5571.         {
  5572.         if (leftJustify)
  5573.             {
  5574.             trackFrame->top += 4;
  5575.             trackFrame->bottom = trackFrame->top + 7;
  5576.             }
  5577.         else
  5578.             {
  5579.             trackFrame->bottom -= 4;
  5580.             trackFrame->top = trackFrame->bottom - 7;
  5581.             }
  5582.         
  5583.         if (includeBackground)
  5584.             {
  5585.             trackFrame->top -= leftJustify ? 4 : 6;
  5586.             trackFrame->bottom += leftJustify ? 6 : 4;
  5587.             }
  5588.         }
  5589.     else
  5590.         {
  5591.         if (leftJustify)
  5592.             {
  5593.             trackFrame->left += 4;
  5594.             trackFrame->right = trackFrame->left + 7;
  5595.             }
  5596.         else
  5597.             {
  5598.             trackFrame->right -= 4;
  5599.             trackFrame->left = trackFrame->right - 7;
  5600.             }
  5601.         
  5602.         if (includeBackground)
  5603.             {
  5604.             trackFrame->left -= leftJustify ? 4 : 6;
  5605.             trackFrame->right += leftJustify ? 6 : 4;
  5606.             }
  5607.         }
  5608.     }
  5609.  
  5610. void AGASlider::GetIndicatorBox(SInt32 indicatorValue, Rect* indicatorBox)
  5611.     {
  5612.     // Return the box that defines the indicator's location
  5613.     // given the specified indicator value.
  5614.  
  5615.     Rect    r = mBounds;
  5616.     SInt32    startPt;
  5617.     SInt32    valuePt;
  5618.     SInt32    stopPt;
  5619.  
  5620.     this->GetIndicatorSpan(indicatorValue, &startPt, &valuePt, &stopPt);
  5621.     
  5622.     if (mIsHorizontal)
  5623.         {
  5624.         r.left = startPt;
  5625.         r.right = stopPt;
  5626.  
  5627.         if (RuntimeJustify(mJustification) == teFlushLeft)
  5628.             {
  5629.             if (mSliderKind == kPointerSlider)
  5630.                 r.top++;
  5631.  
  5632.             r.bottom = r.top + kIndicatorWidth;
  5633.             }
  5634.         else
  5635.             {
  5636.             if (mSliderKind == kPointerSlider)
  5637.                 r.bottom--;
  5638.  
  5639.             r.top = r.bottom - kIndicatorWidth;
  5640.             }
  5641.         }
  5642.     else
  5643.         {
  5644.         r.top = startPt;
  5645.         r.bottom = stopPt;
  5646.  
  5647.         if (RuntimeJustify(mJustification) == teFlushLeft)
  5648.             {
  5649.             if (mSliderKind == kPointerSlider)
  5650.                 r.left++;
  5651.  
  5652.             r.right = r.left + kIndicatorWidth;
  5653.             }
  5654.         else
  5655.             {
  5656.             if (mSliderKind == kPointerSlider)
  5657.                 r.right--;
  5658.  
  5659.             r.left = r.right - kIndicatorWidth;
  5660.             }
  5661.         }
  5662.     
  5663.     *indicatorBox = r;
  5664.     }
  5665.  
  5666. SInt32 AGASlider::GetIndicatorPixelRange(SInt32* proportionalIndicatorPixels)
  5667.     {
  5668.     // Return the pixel range that the center point of the indicator
  5669.     // can travel along the track, and also return the amount of
  5670.     // range reduction that is caused by proportional indicator growth.
  5671.     // Non-proportional indicators use the full track range, minus
  5672.     // the size of the indicator itself.
  5673.  
  5674.     SInt32    range;
  5675.     SInt32    indicatorInset = (mSliderKind == kRectSlider) ? kRectIndicatorPixelInset : kPointerIndicatorPixelInset;
  5676.     
  5677.     *proportionalIndicatorPixels = 0;
  5678.  
  5679.     if (mIsHorizontal)
  5680.         range = mBounds.right - mBounds.left - (2 * (kEndGapSize + indicatorInset)) + 1;
  5681.     else
  5682.         range = mBounds.bottom - mBounds.top - (2 * (kEndGapSize + indicatorInset)) + 1;
  5683.  
  5684.     if (mIsProportional)
  5685.         {
  5686.         SInt32    pagePixels;
  5687.         
  5688.         pagePixels =
  5689.             (range * (((float) mPageSize) / ((float) (mMaximum - mMinimum))));
  5690.         
  5691.         if (pagePixels > 0)
  5692.             {
  5693.             range -= pagePixels;
  5694.             *proportionalIndicatorPixels = pagePixels;
  5695.             }
  5696.         }
  5697.     
  5698.     return range;
  5699.     }
  5700.  
  5701. void AGASlider::GetIndicatorPixelEnds(SInt32* startPt, SInt32* stopPt)
  5702.     {
  5703.     // Return the start and end pixel locations of the indicator
  5704.     // track traveled by the center point of the indicator.
  5705.  
  5706.     SInt32    dontCare;
  5707.     SInt32    range = this->GetIndicatorPixelRange(&dontCare);
  5708.  
  5709.     if (mIsHorizontal)
  5710.         *startPt = ((mBounds.left + mBounds.right) / 2) - (range / 2) - 1;
  5711.     else
  5712.         *startPt = ((mBounds.top + mBounds.bottom) / 2) - (range / 2) - 1;
  5713.  
  5714.     *stopPt = *startPt + range;    // avoid rounding of 1/2 pixel twice
  5715.     }
  5716.  
  5717. void AGASlider::GetIndicatorSpan(SInt32 value, SInt32* startPt, SInt32* valuePt, SInt32* stopPt)
  5718.     {
  5719.     // Return the pixel locations of the indicator's ends and value.
  5720.  
  5721.     SInt32    proportionalIndicatorPixels;
  5722.     SInt32    trackStart;
  5723.     SInt32    trackStop;
  5724.     SInt32    trackRange = this->GetIndicatorPixelRange(&proportionalIndicatorPixels);
  5725.     SInt32    indicatorInset = (mSliderKind == kRectSlider) ? kRectIndicatorPixelInset : kPointerIndicatorPixelInset;
  5726.     
  5727.     this->GetIndicatorPixelEnds(&trackStart, &trackStop);
  5728.     
  5729.     *valuePt = trackStart +
  5730.         (trackRange * (((float) (value - mMinimum)) / ((float) (mMaximum - mMinimum))));
  5731.  
  5732.     *startPt = *valuePt - indicatorInset - (proportionalIndicatorPixels / 2);
  5733.     *stopPt = *startPt + (2 * indicatorInset) + proportionalIndicatorPixels + 1;
  5734.     }
  5735.  
  5736. void AGASlider::DisposeLabels()
  5737.     {
  5738.     // Release the memory allocated for slider labels.
  5739.  
  5740.     if (mLabelStringHandles != NULL)
  5741.         {
  5742.         UInt32    numHandles = ::GetHandleSize(mLabelStringHandles) / sizeof(StringHandle);
  5743.         
  5744.         for (UInt32 i = 0; i < numHandles; i++)
  5745.             ::DisposeHandle((Handle) ((StringHandle*)(*mLabelStringHandles))[i]);
  5746.  
  5747.         ::DisposeHandle(mLabelStringHandles);
  5748.         }
  5749.     }
  5750.  
  5751. //
  5752. // AGAPopupMenu ---------------------------------------------------------------
  5753. //
  5754. // This class implements a standard popup menu look, and handles the
  5755. // mouse by calling PopUpMenuSelect such that the visible menu is
  5756. // located where the AGA says it should.
  5757. //
  5758.  
  5759. AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& textStyle, WidthAdjust adjustment)
  5760. : AGAObject(bounds)
  5761.     {
  5762.     // Construct without a menu installed.
  5763.  
  5764.     mMenuID = 0;
  5765.     mMenuRef = NULL;
  5766.     mMenuRefDisposalKind = kDontDispose;
  5767.     mCurrentItemNo = 1;
  5768.     mWidthAdjust = adjustment;
  5769.     mTextStyle = textStyle;
  5770.     PLstrcpy(mTitle, title);
  5771.     mTitleOffset = titleOffset;
  5772.     mTitleJustification = titleJustification;
  5773.     }
  5774.  
  5775. AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& textStyle, WidthAdjust adjustment, MenuRef itsMenuRef, DisposalKind menuRefDisposalKind)
  5776. : AGAObject(bounds)
  5777.     {
  5778.     // Construct with specified MenuRef.
  5779.  
  5780.     if (itsMenuRef == NULL)
  5781.         mMenuID = 0;
  5782.     else
  5783.         mMenuID = (**itsMenuRef).menuID;
  5784.  
  5785.     mMenuRef = itsMenuRef;
  5786.     mMenuRefDisposalKind = menuRefDisposalKind;
  5787.  
  5788.     mCurrentItemNo = 1;
  5789.     mWidthAdjust = adjustment;
  5790.     mTextStyle = textStyle;
  5791.     PLstrcpy(mTitle, title);
  5792.     mTitleOffset = titleOffset;
  5793.     mTitleJustification = titleJustification;
  5794.     }
  5795.  
  5796. AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& textStyle, WidthAdjust adjustment, SInt16 itemsStringListID, SInt16 newMenuID)
  5797. : AGAObject(bounds)
  5798.     {
  5799.     // Construct with menu built from strings in a 'STR#' resource.
  5800.  
  5801.     mMenuID = newMenuID;
  5802.     mMenuRef = ::NewMenu(newMenuID, "\pAGA");
  5803.     mMenuRefDisposalKind = kDispose;
  5804.     mCurrentItemNo = 1;
  5805.     mWidthAdjust = adjustment;
  5806.     mTextStyle = textStyle;
  5807.     PLstrcpy(mTitle, title);
  5808.     mTitleOffset = titleOffset;
  5809.     mTitleJustification = titleJustification;
  5810.     
  5811.     Handle    stringListHandle = ::GetResource('STR#', itemsStringListID);
  5812.     if (stringListHandle != NULL)
  5813.         {
  5814.         SInt16    numStrings = **((SInt16 **) stringListHandle);
  5815.         
  5816.         for (SInt16 stringIndex = 1; stringIndex <= numStrings; stringIndex++)
  5817.             {
  5818.             Str255    aString;
  5819.             
  5820.             ::GetIndString(aString, itemsStringListID, stringIndex);
  5821.             
  5822.             // Use SetMenuItemText to avoid metacharacter interpretation.
  5823.             ::AppendMenu(mMenuRef, "\pXXX");
  5824.             ::SetMenuItemText(mMenuRef, stringIndex, aString);
  5825.             }
  5826.         }
  5827.     }
  5828.  
  5829. AGAPopupMenu::AGAPopupMenu(Rect* bounds, SInt16 titleOffset, StringPtr title, SInt32 titleJustification, const AGATextStyle& textStyle, WidthAdjust adjustment, ResType appendResourceType, SInt16 newMenuID)
  5830. : AGAObject(bounds)
  5831.     {
  5832.     // Construct with menu built from specified appended resource type.
  5833.     // Typical use is for a Fonts menu, using resource type 'FOND'.
  5834.  
  5835.     mMenuID = newMenuID;
  5836.     mMenuRef = ::NewMenu(newMenuID, "\pAGA");
  5837.     mMenuRefDisposalKind = kDispose;
  5838.     mCurrentItemNo = 1;
  5839.     mWidthAdjust = adjustment;
  5840.     mTextStyle = textStyle;
  5841.     PLstrcpy(mTitle, title);
  5842.     mTitleOffset = titleOffset;
  5843.     mTitleJustification = titleJustification;
  5844.     
  5845.     ::AppendResMenu(mMenuRef, appendResourceType);
  5846.     }
  5847.  
  5848. AGAPopupMenu::~AGAPopupMenu()
  5849.     {
  5850.     // Destruct by cleaning up the menu data.
  5851.     // This depends on how the menu was created.
  5852.  
  5853.     this->DisposeExistingMenuRef();
  5854.     }
  5855.  
  5856. void AGAPopupMenu::DisposeExistingMenuRef()
  5857.     {
  5858.     // Clean up the menu data based on how it was created
  5859.     // or how the client code specified.
  5860.  
  5861.     if (mMenuRef != NULL)
  5862.         {
  5863.         if (mMenuRefDisposalKind == kDispose)
  5864.             ::DisposeMenu(mMenuRef);
  5865.         else if (mMenuRefDisposalKind == kRelease)
  5866.             ::ReleaseResource((Handle) mMenuRef);
  5867.         }
  5868.  
  5869.     mMenuRefDisposalKind = kDontDispose;
  5870.     }
  5871.  
  5872. void AGAPopupMenu::SetMenuRef(MenuRef itsMenuRef, DisposalKind menuRefDisposalKind)
  5873.     {
  5874.     // Install the specified MenuRef.
  5875.  
  5876.     this->DisposeExistingMenuRef();
  5877.  
  5878.     if (itsMenuRef == NULL)
  5879.         mMenuID = 0;
  5880.     else
  5881.         mMenuID = (**itsMenuRef).menuID;
  5882.  
  5883.     mMenuRef = itsMenuRef;
  5884.     mMenuRefDisposalKind = menuRefDisposalKind;
  5885.  
  5886.     mCurrentItemNo = 1;
  5887.     }
  5888.  
  5889. void AGAPopupMenu::SetWidthAdjustment(WidthAdjust adjustment)
  5890.     {
  5891.     // Set the width adjustment, which determines how wide
  5892.     // the closed menu appears.
  5893.  
  5894.     mWidthAdjust = adjustment;
  5895.     }
  5896.  
  5897. void AGAPopupMenu::DrawObject()
  5898.     {
  5899.     // Draw the unpressed popup menu "button".
  5900.  
  5901.     this->DrawButton(kNotPressed);
  5902.     }
  5903.  
  5904. Boolean AGAPopupMenu::TrackMouse(Point mouseLocation)
  5905.     {
  5906.     // Track the mouse in the popup, and return true
  5907.     // if it caused the current popup selection to change.
  5908.  
  5909.     Boolean    selectionChanged;
  5910.     SInt32    menuResult;
  5911.     Point    globalOrigin;
  5912.     
  5913.     this->DrawButton(kPressed);
  5914.     
  5915.     ::SetPt(&globalOrigin, mBounds.left + mTitleOffset, mBounds.bottom);
  5916.     ::LocalToGlobal(&globalOrigin);
  5917.  
  5918.     ::InsertMenu(mMenuRef, -1);            // put it in the hierarchical list
  5919.  
  5920.     ::CheckItem(mMenuRef, mCurrentItemNo, TRUE);
  5921.     menuResult = ::PopUpMenuSelect(mMenuRef, globalOrigin.v, globalOrigin.h + 1, 1);
  5922.     ::CheckItem(mMenuRef, mCurrentItemNo, FALSE);
  5923.  
  5924.     ::DeleteMenu((**mMenuRef).menuID);    // get it out of the hierarchical list
  5925.  
  5926.     selectionChanged = (menuResult != 0);
  5927.  
  5928.     if (selectionChanged)
  5929.         this->SetCurrentItemNo(menuResult & 0x0000FFFF, kDontRedraw);
  5930.     
  5931.     this->DrawButton(kNotPressed);
  5932.  
  5933.     return selectionChanged;
  5934.     }
  5935.  
  5936. SInt16 AGAPopupMenu::GetCurrentItemNo()
  5937.     {
  5938.     // Return the currently selected item index (1-based).
  5939.  
  5940.     return mCurrentItemNo;
  5941.     }
  5942.  
  5943. void AGAPopupMenu::SetCurrentItemNo(SInt16 newItemNo, Boolean redraw)
  5944.     {
  5945.     // Set the current item index (1-based), optionally redraw.
  5946.  
  5947.     mCurrentItemNo = newItemNo;
  5948.     
  5949.     if (redraw)
  5950.         this->DrawButton(kNotPressed);
  5951.     }
  5952.  
  5953. void AGAPopupMenu::GetCurrentItemText(StringPtr itemText)
  5954.     {
  5955.     // Return the menu item text of the currently selected item.
  5956.  
  5957.     itemText[0] = 0;
  5958.     
  5959.     if (mMenuRef != NULL)
  5960.         ::GetMenuItemText(mMenuRef, this->GetCurrentItemNo(), itemText);
  5961.     }
  5962.  
  5963. Boolean AGAPopupMenu::SetCurrentItemText(StringPtr itemTextToMatch, Boolean redraw)
  5964.     {
  5965.     // Set the current item index to the item whose text
  5966.     // matches the specified string. Optionally redraw.
  5967.  
  5968.     Boolean    wasMatchFound = FALSE;
  5969.     SInt16    numItems = 0;
  5970.  
  5971.     if (mMenuRef != NULL)
  5972.         numItems = ::CountMenuItems(mMenuRef);
  5973.  
  5974.     for (SInt16 itemIndex = 1; itemIndex <= numItems; itemIndex++)
  5975.         {
  5976.         Str255    itemText;
  5977.  
  5978.         ::GetMenuItemText(mMenuRef, itemIndex, itemText);
  5979.  
  5980.         if (::EqualString(itemText, itemTextToMatch, TRUE, TRUE))
  5981.             {
  5982.             wasMatchFound = TRUE;
  5983.             this->SetCurrentItemNo(itemIndex, redraw);
  5984.             break;
  5985.             }
  5986.         }
  5987.  
  5988.     return wasMatchFound;
  5989.     }
  5990.  
  5991. void AGAPopupMenu::DrawButton(Boolean pressed)
  5992.     {
  5993.     // Draw the popup button in the specified state.
  5994.  
  5995.     GDIterator    iter;
  5996.     Boolean        deep;
  5997.  
  5998.     while (iter.More(deep))
  5999.         {
  6000.         if (! mEnabled)
  6001.             this->DrawButtonDisabled(deep);
  6002.         else if (pressed)
  6003.             this->DrawButtonPressed(deep);
  6004.         else
  6005.             this->DrawButtonNormal(deep);
  6006.         }
  6007.     }
  6008.  
  6009. void AGAPopupMenu::DrawButtonNormal(Boolean deep)
  6010.     {
  6011.     CleansePen();
  6012.  
  6013.     // Draw the popup button in enabled/unpressed state.
  6014.  
  6015.     Rect    r;
  6016.     Str255    currentItemText;
  6017.     
  6018.     this->GetCurrentItemText(currentItemText);
  6019.     this->GetButtonBounds(&r);
  6020.     
  6021.     ::PenSize(1, 1);
  6022.  
  6023.     if (deep)
  6024.         {
  6025.         // Fill the interior.
  6026.         ::InsetRect(&r, 1, 1);
  6027.         ::RGBForeColor(&gAGARamp[r2]);
  6028.         ::PaintRect(&r);
  6029.         ::InsetRect(&r, -1, -1);
  6030.         
  6031.         // Draw the frame.
  6032.         ::MoveTo(r.left + 1, r.top + 1);
  6033.         ::RGBForeColor(&gAGARamp[rB]);
  6034.         ::Line(0, 0);
  6035.         ::Move(1, -1);
  6036.         ::RGBForeColor(&gAGARamp[r12]);
  6037.         ::Line(0, 0);
  6038.         ::Move(1, 0);
  6039.         ::RGBForeColor(&gAGARamp[rB]);
  6040.         ::Line(r.right - r.left - 6, 0);
  6041.         ::RGBForeColor(&gAGARamp[r12]);
  6042.         ::Line(0, 0);
  6043.         ::Move(1, 1);
  6044.         ::RGBForeColor(&gAGARamp[rB]);
  6045.         ::Line(0, 0);
  6046.         ::Move(1, 1);
  6047.         ::RGBForeColor(&gAGARamp[r12]);
  6048.         ::Line(0, 0);
  6049.         ::Move(0, 1);
  6050.         ::RGBForeColor(&gAGARamp[rB]);
  6051.         ::Line(0, r.bottom - r.top - 6);
  6052.         ::RGBForeColor(&gAGARamp[r12]);
  6053.         ::Line(0, 0);
  6054.         ::Move(-1, 1);
  6055.         ::RGBForeColor(&gAGARamp[rB]);
  6056.         ::Line(0, 0);
  6057.         ::Move(-1, 1);
  6058.         ::RGBForeColor(&gAGARamp[r12]);
  6059.         ::Line(0, 0);
  6060.         ::Move(-1, 0);
  6061.         ::RGBForeColor(&gAGARamp[rB]);
  6062.         ::Line(- (r.right - r.left - 6), 0);
  6063.         ::RGBForeColor(&gAGARamp[r12]);
  6064.         ::Line(0, 0);
  6065.         ::Move(-1, -1);
  6066.         ::RGBForeColor(&gAGARamp[rB]);
  6067.         ::Line(0, 0);
  6068.         ::Move(-1, -1);
  6069.         ::RGBForeColor(&gAGARamp[r12]);
  6070.         ::Line(0, 0);
  6071.         ::Move(0, -1);
  6072.         ::RGBForeColor(&gAGARamp[rB]);
  6073.         ::Line(0, -(r.bottom - r.top - 6));
  6074.         ::RGBForeColor(&gAGARamp[r12]);
  6075.         ::Line(0, 0);
  6076.         
  6077.         if (r.right - r.left > kPopupArrowSectionWidth)
  6078.             {
  6079.             // Add flat section inner pixels.
  6080.             ::RGBForeColor(&gAGARamp[rW]);
  6081.             ::MoveTo(r.left + 1, r.bottom - 3);
  6082.             ::LineTo(r.left + 1, r.top + 2);
  6083.             ::Move(1, -1);
  6084.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 1);
  6085.             ::RGBForeColor(&gAGARamp[r1]);
  6086.             ::Line(0, 0);
  6087.             ::RGBForeColor(&gAGARamp[r5]);
  6088.             ::MoveTo(r.left + 2, r.bottom - 2);
  6089.             ::LineTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
  6090.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
  6091.             
  6092.             // Add arrow section left corners
  6093.             ::RGBForeColor(&gAGARamp[r4]);
  6094.             ::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 2);
  6095.             ::Line(0, 0);
  6096.             ::RGBForeColor(&gAGARamp[r2]);
  6097.             ::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.top + 1);
  6098.             ::Line(0, 0);
  6099.             }
  6100.  
  6101.         // Add arrow section shading.
  6102.         ::RGBForeColor(&gAGARamp[r8]);
  6103.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 2);
  6104.         ::LineTo(r.right - 3, r.bottom - 2);
  6105.         ::Line(0, -1);
  6106.         ::Line(1, 0);
  6107.         ::LineTo(r.right - 2, r.top + 3);
  6108.         ::Move(-1, -2);
  6109.         ::RGBForeColor(&gAGARamp[r4]);
  6110.         ::Line(1, 1);
  6111.         ::RGBForeColor(&gAGARamp[r5]);
  6112.         ::Line(-1, 1);
  6113.         ::LineTo(r.right - 3, r.bottom - 4);
  6114.         ::Move(-1, 1);
  6115.         ::LineTo(r.right - kPopupArrowSectionWidth + 3, r.bottom - 3);
  6116.         ::RGBForeColor(&gAGARamp[rW]);
  6117.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 4);
  6118.         ::LineTo(r.right - kPopupArrowSectionWidth + 2, r.top + 2);
  6119.         ::LineTo(r.right - 4, r.top + 2);
  6120.         }
  6121.     else    // 1-bit
  6122.         {
  6123.         ::RGBForeColor(&gAGARamp[rW]);
  6124.         ::PaintRoundRect(&r, 7, 7);
  6125.         ::RGBForeColor(&gAGARamp[rB]);
  6126.         ::FrameRoundRect(&r, 7, 7);
  6127.         }
  6128.     
  6129.     // Add arrow.
  6130.     ::RGBForeColor(&gAGARamp[rB]);
  6131.     ::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + 8);
  6132.     ::Line(8, 0);
  6133.     ::Move(-1, 1);
  6134.     ::Line(-6, 0);
  6135.     ::Move(1, 1);
  6136.     ::Line(4, 0);
  6137.     ::Move(-1, 1);
  6138.     ::Line(-2, 0);
  6139.     ::Line(1, 1);
  6140.  
  6141.     if (r.right - r.left > kPopupArrowSectionWidth)
  6142.         {
  6143.         // Draw the current item text.
  6144.         r.left += 7;
  6145.         r.right -= kPopupArrowSectionWidth;
  6146.         AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kNormalOutput, deep, mTextStyle);
  6147.         }
  6148.  
  6149.     // If the popup has a title, draw it next to the button.    
  6150.     if (mTitle[0] != 0)
  6151.         {
  6152.         this->GetTitleBounds(&r);
  6153.         AGAStringOut(mTitle, &r, truncEnd, mTitleJustification, kNormalOutput, deep, mTextStyle);
  6154.         }
  6155.  
  6156.     CleansePen();
  6157.     }
  6158.  
  6159. void AGAPopupMenu::DrawButtonPressed(Boolean deep)
  6160.     {
  6161.     CleansePen();
  6162.  
  6163.     // Draw the popup button in enabled/pressed state.
  6164.  
  6165.     Rect    r;
  6166.     Str255    currentItemText;
  6167.     
  6168.     this->GetCurrentItemText(currentItemText);
  6169.     this->GetButtonBounds(&r);
  6170.     
  6171.     ::PenSize(1, 1);
  6172.  
  6173.     if (deep)
  6174.         {
  6175.         // Fill the interior.
  6176.         ::InsetRect(&r, 1, 1);
  6177.         ::RGBForeColor(&gAGARamp[r9]);
  6178.         ::PaintRect(&r);
  6179.         ::InsetRect(&r, -1, -1);
  6180.         
  6181.         // Draw the frame.
  6182.         ::MoveTo(r.left + 1, r.top + 1);
  6183.         ::RGBForeColor(&gAGARamp[rB]);
  6184.         ::Line(0, 0);
  6185.         ::Move(1, -1);
  6186.         ::RGBForeColor(&gAGARamp[r12]);
  6187.         ::Line(0, 0);
  6188.         ::Move(1, 0);
  6189.         ::RGBForeColor(&gAGARamp[rB]);
  6190.         ::Line(r.right - r.left - 6, 0);
  6191.         ::RGBForeColor(&gAGARamp[r12]);
  6192.         ::Line(0, 0);
  6193.         ::Move(1, 1);
  6194.         ::RGBForeColor(&gAGARamp[rB]);
  6195.         ::Line(0, 0);
  6196.         ::Move(1, 1);
  6197.         ::RGBForeColor(&gAGARamp[r12]);
  6198.         ::Line(0, 0);
  6199.         ::Move(0, 1);
  6200.         ::RGBForeColor(&gAGARamp[rB]);
  6201.         ::Line(0, r.bottom - r.top - 6);
  6202.         ::RGBForeColor(&gAGARamp[r12]);
  6203.         ::Line(0, 0);
  6204.         ::Move(-1, 1);
  6205.         ::RGBForeColor(&gAGARamp[rB]);
  6206.         ::Line(0, 0);
  6207.         ::Move(-1, 1);
  6208.         ::RGBForeColor(&gAGARamp[r12]);
  6209.         ::Line(0, 0);
  6210.         ::Move(-1, 0);
  6211.         ::RGBForeColor(&gAGARamp[rB]);
  6212.         ::Line(- (r.right - r.left - 6), 0);
  6213.         ::RGBForeColor(&gAGARamp[r12]);
  6214.         ::Line(0, 0);
  6215.         ::Move(-1, -1);
  6216.         ::RGBForeColor(&gAGARamp[rB]);
  6217.         ::Line(0, 0);
  6218.         ::Move(-1, -1);
  6219.         ::RGBForeColor(&gAGARamp[r12]);
  6220.         ::Line(0, 0);
  6221.         ::Move(0, -1);
  6222.         ::RGBForeColor(&gAGARamp[rB]);
  6223.         ::Line(0, -(r.bottom - r.top - 6));
  6224.         ::RGBForeColor(&gAGARamp[r12]);
  6225.         ::Line(0, 0);
  6226.         
  6227.         if (r.right - r.left > kPopupArrowSectionWidth)
  6228.             {
  6229.             // Add flat section inner pixels.
  6230.             ::RGBForeColor(&gAGARamp[r10]);
  6231.             ::MoveTo(r.left + 1, r.bottom - 3);
  6232.             ::LineTo(r.left + 1, r.top + 2);
  6233.             ::Line(1, 0);
  6234.             ::Line(0, -1);
  6235.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 1);
  6236.             ::RGBForeColor(&gAGARamp[r8]);
  6237.             ::MoveTo(r.left + 2, r.bottom - 2);
  6238.             ::LineTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
  6239.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
  6240.             
  6241.             // Add arrow section left corners
  6242.             ::RGBForeColor(&gAGARamp[r11]);
  6243.             ::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 2);
  6244.             ::Line(0, 0);
  6245.             ::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.top + 1);
  6246.             ::Line(0, 0);
  6247.             }
  6248.  
  6249.         // Add arrow section shading.
  6250.         ::RGBForeColor(&gAGARamp[r7]);
  6251.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 2);
  6252.         ::LineTo(r.right - 3, r.bottom - 2);
  6253.         ::Line(0, -1);
  6254.         ::Line(1, 0);
  6255.         ::LineTo(r.right - 2, r.top + 2);
  6256.         ::Move(-1, 1);
  6257.         ::RGBForeColor(&gAGARamp[r8]);
  6258.         ::LineTo(r.right - 3, r.bottom - 4);
  6259.         ::Move(-1, 1);
  6260.         ::LineTo(r.right - kPopupArrowSectionWidth + 3, r.bottom - 3);
  6261.         ::RGBForeColor(&gAGARamp[r10]);
  6262.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 4);
  6263.         ::LineTo(r.right - kPopupArrowSectionWidth + 2, r.top + 2);
  6264.         ::LineTo(r.right - 4, r.top + 2);
  6265.         ::RGBForeColor(&gAGARamp[r11]);
  6266.         ::MoveTo(r.right - kPopupArrowSectionWidth + 1, r.bottom - 3);
  6267.         ::LineTo(r.right - kPopupArrowSectionWidth + 1, r.top + 2);
  6268.         ::Move(1, -1);
  6269.         ::LineTo(r.right - 3, r.top + 1);
  6270.         }
  6271.     else    // 1-bit
  6272.         {
  6273.         ::RGBForeColor(&gAGARamp[rB]);
  6274.         ::PaintRoundRect(&r, 7, 7);
  6275.         }
  6276.  
  6277.     // Add arrow.
  6278.     
  6279.     ::RGBForeColor(&gAGARamp[rW]);
  6280.     ::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + 8);
  6281.     ::Line(8, 0);
  6282.     ::Move(-1, 1);
  6283.     ::Line(-6, 0);
  6284.     ::Move(1, 1);
  6285.     ::Line(4, 0);
  6286.     ::Move(-1, 1);
  6287.     ::Line(-2, 0);
  6288.     ::Line(1, 1);
  6289.  
  6290.     if (r.right - r.left > kPopupArrowSectionWidth)
  6291.         {
  6292.         // Draw the current item text.
  6293.         r.left += 7;
  6294.         r.right -= kPopupArrowSectionWidth;
  6295.         AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kInverseOutput, deep, mTextStyle);
  6296.         }
  6297.  
  6298.     // (No need to draw the title, since it does not change
  6299.     //  upon pressing the button.)
  6300.  
  6301.     CleansePen();
  6302.     }
  6303.  
  6304. void AGAPopupMenu::DrawButtonDisabled(Boolean deep)
  6305.     {
  6306.     CleansePen();
  6307.  
  6308.     // Draw the popup button in disabled/unpressed state.
  6309.  
  6310.     Rect    r;
  6311.     Str255    currentItemText;
  6312.     
  6313.     this->GetCurrentItemText(currentItemText);
  6314.     this->GetButtonBounds(&r);
  6315.     
  6316.     ::PenSize(1, 1);
  6317.  
  6318.     if (deep)
  6319.         {
  6320.         // Fill the interior.
  6321.         ::InsetRect(&r, 1, 1);
  6322.         ::RGBForeColor(&gAGARamp[r2]);
  6323.         ::PaintRect(&r);
  6324.         ::InsetRect(&r, -1, -1);
  6325.         
  6326.         // Draw the frame.
  6327.         ::MoveTo(r.left + 1, r.top + 1);
  6328.         ::RGBForeColor(&gAGARamp[r7]);
  6329.         ::Line(0, 0);
  6330.         ::Move(1, -1);
  6331.         ::Line(0, 0);
  6332.         ::Move(1, 0);
  6333.         ::Line(r.right - r.left - 6, 0);
  6334.         ::Line(0, 0);
  6335.         ::Move(1, 1);
  6336.         ::Line(0, 0);
  6337.         ::Move(1, 1);
  6338.         ::Line(0, 0);
  6339.         ::Move(0, 1);
  6340.         ::Line(0, r.bottom - r.top - 6);
  6341.         ::Line(0, 0);
  6342.         ::Move(-1, 1);
  6343.         ::Line(0, 0);
  6344.         ::Move(-1, 1);
  6345.         ::Line(0, 0);
  6346.         ::Move(-1, 0);
  6347.         ::Line(- (r.right - r.left - 6), 0);
  6348.         ::Line(0, 0);
  6349.         ::Move(-1, -1);
  6350.         ::Line(0, 0);
  6351.         ::Move(-1, -1);
  6352.         ::Line(0, 0);
  6353.         ::Move(0, -1);
  6354.         ::Line(0, -(r.bottom - r.top - 6));
  6355.         ::Line(0, 0);
  6356.         
  6357.         if (r.right - r.left > kPopupArrowSectionWidth)
  6358.             {
  6359.             // Add flat section inner pixels.
  6360.             ::RGBForeColor(&gAGARamp[r1]);
  6361.             ::MoveTo(r.left + 1, r.bottom - 3);
  6362.             ::LineTo(r.left + 1, r.top + 2);
  6363.             ::Line(1, 0);
  6364.             ::Line(0, -1);
  6365.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 1);
  6366.             ::RGBForeColor(&gAGARamp[r5]);
  6367.             ::MoveTo(r.left + 2, r.bottom - 2);
  6368.             ::LineTo(r.right - kPopupArrowSectionWidth, r.bottom - 2);
  6369.             ::LineTo(r.right - kPopupArrowSectionWidth, r.top + 2);
  6370.             }
  6371.  
  6372.         // Add arrow section shading.
  6373.         ::RGBForeColor(&gAGARamp[r5]);
  6374.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 2);
  6375.         ::LineTo(r.right - 3, r.bottom - 2);
  6376.         ::Line(0, -1);
  6377.         ::Line(1, 0);
  6378.         ::LineTo(r.right - 2, r.top + 2);
  6379.         ::Move(-1, 1);
  6380.         ::RGBForeColor(&gAGARamp[r4]);
  6381.         ::LineTo(r.right - 3, r.bottom - 4);
  6382.         ::Move(-1, 1);
  6383.         ::LineTo(r.right - kPopupArrowSectionWidth + 3, r.bottom - 3);
  6384.         ::RGBForeColor(&gAGARamp[r1]);
  6385.         ::MoveTo(r.right - kPopupArrowSectionWidth + 2, r.bottom - 4);
  6386.         ::LineTo(r.right - kPopupArrowSectionWidth + 2, r.top + 2);
  6387.         ::LineTo(r.right - 4, r.top + 2);
  6388.         }
  6389.     else    // 1-bit
  6390.         {
  6391.         ::RGBForeColor(&gAGARamp[rW]);
  6392.         ::PaintRoundRect(&r, 7, 7);
  6393.         ::RGBForeColor(&gAGARamp[rB]);
  6394.         ::FrameRoundRect(&r, 7, 7);
  6395.         }
  6396.  
  6397.     // Add arrow.
  6398.     ::RGBForeColor(&gAGARamp[r7]);
  6399.     ::MoveTo(r.right - kPopupArrowSectionWidth + 6, r.top + 8);
  6400.     ::Line(8, 0);
  6401.     ::Move(-1, 1);
  6402.     ::Line(-6, 0);
  6403.     ::Move(1, 1);
  6404.     ::Line(4, 0);
  6405.     ::Move(-1, 1);
  6406.     ::Line(-2, 0);
  6407.     ::Line(1, 1);
  6408.  
  6409.     if (r.right - r.left > kPopupArrowSectionWidth)
  6410.         {
  6411.         // Draw the current item text.
  6412.         r.left += 7;
  6413.         r.right -= kPopupArrowSectionWidth;
  6414.         AGAStringOut(currentItemText, &r, truncEnd, teFlushDefault, kDisabledOutput, deep, mTextStyle);
  6415.         }
  6416.     
  6417.     // If the popup has a title, draw it next to the button.    
  6418.     if (mTitle[0] != 0)
  6419.         {
  6420.         this->GetTitleBounds(&r);
  6421.         AGAStringOut(mTitle, &r, truncEnd, mTitleJustification, kDisabledOutput, deep, mTextStyle);
  6422.         }
  6423.     
  6424.     if (! deep)
  6425.         {
  6426.         ::RGBForeColor(&gAGARamp[rB]);
  6427.         ::PenPat(&qd.gray);
  6428.         ::PenMode(patBic);
  6429.         ::PaintRect(&mBounds);
  6430.  
  6431.         ::PenNormal();
  6432.         }
  6433.  
  6434.     CleansePen();
  6435.     }
  6436.  
  6437. void AGAPopupMenu::GetButtonBounds(Rect* buttonBounds)
  6438.     {
  6439.     // Return the bounds of the popup button. We may need
  6440.     // to check the actual menu's width, depending on the
  6441.     // width adjustment specifier.
  6442.  
  6443.     *buttonBounds = mBounds;
  6444.     buttonBounds->left += mTitleOffset;
  6445.     
  6446.     if ((mMenuRef != NULL) && (mWidthAdjust != kFixedWidth))
  6447.         {
  6448.         ::CalcMenuSize(mMenuRef);
  6449.         buttonBounds->right = MinSInt16(mBounds.right, buttonBounds->left + 3 + (**mMenuRef).menuWidth + mWidthAdjust);
  6450.         }
  6451.     }
  6452.  
  6453. void AGAPopupMenu::GetTitleBounds(Rect* titleBounds)
  6454.     {
  6455.     // Return the bounds of the title area.
  6456.  
  6457.     *titleBounds = mBounds;
  6458.     
  6459.     titleBounds->right = titleBounds->left + mTitleOffset - 3;
  6460.     }
  6461.  
  6462. //
  6463. // AGALittleArrows ---------------------------------------------------------------
  6464. //
  6465. // This class implements a little arrows control.
  6466. //
  6467.  
  6468. AGALittleArrows::AGALittleArrows(Rect* bounds)
  6469. : AGAObject(bounds)
  6470.     {
  6471.     mNotificationRoutine = NULL;
  6472.     mUserData = 0;
  6473.     }
  6474.  
  6475. AGALittleArrows::~AGALittleArrows()
  6476.     {
  6477.     }
  6478.  
  6479. void AGALittleArrows::InstallNotificationRoutine(AGALittleArrowsNotifyPtr notificationRoutine, void* userData)
  6480.     {
  6481.     // Install the supplied function pointer and user data to
  6482.     // be called during notification.
  6483.  
  6484.     mNotificationRoutine = notificationRoutine;
  6485.     mUserData = userData;
  6486.     }
  6487.  
  6488. void AGALittleArrows::DrawObject()
  6489.     {
  6490.     // Draw the arrows in normal unpressed state.
  6491.  
  6492.     this->DrawButton(kNoArrowPressed);
  6493.     }
  6494.  
  6495. Boolean AGALittleArrows::TrackMouse(Point mouseLocation)
  6496.     {
  6497.     // Track the mouse in the appropriate arrow. Little arrows
  6498.     // always return true because the tracking is always successful.
  6499.  
  6500.     return this->TrackPart(mouseLocation, this->TrackTestPart(mouseLocation));
  6501.     }
  6502.  
  6503. void AGALittleArrows::DrawButton(SInt32 pressedPart)
  6504.     {
  6505.     CleansePen();
  6506.  
  6507.     // Draw the arrows in the specified press state. The
  6508.     // state may indicate that either or no arrow is pressed.
  6509.  
  6510.     enum { Frame, Fill, TL, BR, Arrow, kNumArrowColors };
  6511.  
  6512.     UInt8    colorIndexes[kNumArrowColors];
  6513.     
  6514.     GDIterator    iter;
  6515.     Boolean        deep;
  6516.  
  6517.     while (iter.More(deep))
  6518.         {
  6519.         Rect    r = mBounds;
  6520.         
  6521.         r.right = r.left + kLittleArrowWidth;
  6522.         r.bottom = r.top + kLittleArrowHeight;
  6523.         
  6524.         for (UInt32 i = 0; i < 2; i++)
  6525.             {
  6526.             if (deep)
  6527.                 {
  6528.                 if (mEnabled)
  6529.                     {
  6530.                     if (((pressedPart == kUpArrowPressed) && (i == 0)) ||
  6531.                         ((pressedPart == kDownArrowPressed) && (i == 1)))
  6532.                         {
  6533.                         colorIndexes[Frame] = rB;
  6534.                         colorIndexes[Fill] = r8;
  6535.                         colorIndexes[TL] = r10;
  6536.                         colorIndexes[BR] = r6;
  6537.                         colorIndexes[Arrow] = rW;
  6538.                         }
  6539.                     else if (((pressedPart != kUpArrowPressed) && (i == 0)) ||
  6540.                         ((pressedPart != kDownArrowPressed) && (i == 1)))
  6541.                         {
  6542.                         colorIndexes[Frame] = rB;
  6543.                         colorIndexes[Fill] = r2;
  6544.                         colorIndexes[TL] = rW;
  6545.                         colorIndexes[BR] = r5;
  6546.                         colorIndexes[Arrow] = rB;
  6547.                         }
  6548.                     }
  6549.                 else    // disabled
  6550.                     {
  6551.                     colorIndexes[Frame] = r7;
  6552.                     colorIndexes[Fill] = r2;
  6553.                     colorIndexes[TL] = r1;
  6554.                     colorIndexes[BR] = r5;
  6555.                     colorIndexes[Arrow] = r7;
  6556.                     }
  6557.                 
  6558.                 
  6559.                 ::RGBForeColor(&gAGARamp[colorIndexes[Frame]]);
  6560.                 ::FrameRect(&r);
  6561.                 
  6562.                 ::InsetRect(&r, 1, 1);
  6563.                 ::RGBForeColor(&gAGARamp[colorIndexes[Fill]]);
  6564.                 ::PaintRect(&r);
  6565.                 ::InsetRect(&r, -1, -1);
  6566.                 
  6567.                 ::RGBForeColor(&gAGARamp[colorIndexes[TL]]);
  6568.                 ::MoveTo(r.left + 1, r.bottom - 3);
  6569.                 ::LineTo(r.left + 1, r.top + 1);
  6570.                 ::LineTo(r.right - 3, r.top + 1);
  6571.                 
  6572.                 ::RGBForeColor(&gAGARamp[colorIndexes[BR]]);
  6573.                 ::MoveTo(r.left + 2, r.bottom - 2);
  6574.                 ::LineTo(r.right - 2, r.bottom - 2);
  6575.                 ::LineTo(r.right - 2, r.top + 2);
  6576.                 
  6577.                 ::RGBForeColor(&gAGARamp[colorIndexes[Arrow]]);
  6578.                 }
  6579.             else    // 1-bit
  6580.                 {
  6581.                 if (((pressedPart == kUpArrowPressed) && (i == 0)) ||
  6582.                     ((pressedPart == kDownArrowPressed) && (i == 1)))
  6583.                     {
  6584.                     ::RGBForeColor(&gAGARamp[rB]);
  6585.                     ::PaintRect(&r);
  6586.                     ::RGBForeColor(&gAGARamp[rW]);
  6587.                     }
  6588.                 else
  6589.                     {
  6590.                     ::RGBForeColor(&gAGARamp[rW]);
  6591.                     ::PaintRect(&r);
  6592.                     ::RGBForeColor(&gAGARamp[rB]);
  6593.                     ::FrameRect(&r);
  6594.                     }
  6595.                 }
  6596.  
  6597.             ::MoveTo(r.left + 3, r.top + 7 - (i*3));
  6598.             ::Line(6, 0);
  6599.             ::Move(-1, -1 + (2*i));
  6600.             ::Line(-4, 0);
  6601.             ::Move(1, -1 + (2*i));
  6602.             ::Line(2, 0);
  6603.             ::Move(-1, -1 + (2*i));
  6604.             ::Line(0, 0);
  6605.             
  6606.             ::OffsetRect(&r, 0, kLittleArrowHeight - 1);
  6607.             }
  6608.  
  6609.         if ((! mEnabled) && ! deep)
  6610.             {
  6611.             ::RGBForeColor(&gAGARamp[rB]);
  6612.             ::PenPat(&qd.gray);
  6613.             ::PenMode(patBic);
  6614.             ::PaintRect(&mBounds);
  6615.  
  6616.             ::PenNormal();
  6617.             }
  6618.         }
  6619.  
  6620.     CleansePen();
  6621.     }
  6622.  
  6623. Boolean AGALittleArrows::TrackPart(Point mouseLocation, SInt32 partHit)
  6624.     {
  6625.     // Track the mouse in the specified arrow. Little arrows always
  6626.     // return true because the tracking is always successful.
  6627.  
  6628.     Boolean    wasIn = FALSE;
  6629.     Boolean    isIn = TRUE;
  6630.     Boolean    isButtonDown = TRUE;    // ensure at least one time through
  6631.     Point    newMouseLocation;
  6632.     UInt32    accelerationDelay = 18;    // will divide by 2 each time
  6633.     
  6634.     while (isButtonDown)
  6635.         {
  6636.         if (isIn)
  6637.             this->NotifyDelta(partHit);
  6638.  
  6639.         ::GetMouse(&newMouseLocation);    // gives local coordinates
  6640.         
  6641.         isIn = (this->TrackTestPart(newMouseLocation) == partHit);
  6642.         
  6643.         if (isIn != wasIn)
  6644.             this->DrawButton(isIn ? partHit : kNoArrowPressed);
  6645.         
  6646.         wasIn = isIn;
  6647.         
  6648.         if (isButtonDown && (accelerationDelay != 0))
  6649.             {
  6650.             DelayFutureWhileStillDown(accelerationDelay);
  6651.             accelerationDelay = accelerationDelay >> 1;    // divide by 2
  6652.             }
  6653.  
  6654.         isButtonDown = ::StillDown();
  6655.         }
  6656.     
  6657.     if (isIn)    // if finished IN, restore normal appearance
  6658.         this->DrawButton(kNoArrowPressed);
  6659.     
  6660.     return TRUE;
  6661.     }
  6662.  
  6663. SInt32 AGALittleArrows::TrackTestPart(Point mouseLocation)
  6664.     {
  6665.     // Return the part value where the mouse would hit.
  6666.  
  6667.     if ((mouseLocation.h >= mBounds.left + kLittleArrowWidth) ||
  6668.         (mouseLocation.h < mBounds.left) ||
  6669.         (mouseLocation.v >= mBounds.top + kLittleArrowTotalHeight) ||
  6670.         (mouseLocation.v < mBounds.top))
  6671.         return kNoArrowPressed;
  6672.     else if (mouseLocation.v < mBounds.top + kLittleArrowHeight)
  6673.         return kUpArrowPressed;
  6674.     else
  6675.         return kDownArrowPressed;
  6676.     }
  6677.  
  6678. void AGALittleArrows::NotifyDelta(SInt32 partHit)
  6679.     {
  6680.     // Call the installed notification routine, if any, with
  6681.     // the installed user data and our part hit, which is the
  6682.     // value delta (-1 or 1).
  6683.  
  6684.     if (mNotificationRoutine != NULL)
  6685.         (*(mNotificationRoutine))(this, partHit, mUserData);
  6686.     }
  6687.  
  6688. //
  6689. // AGADisclosureTriangle ---------------------------------------------------------------
  6690. //
  6691. // This class implements a disclosure triangle.
  6692. //
  6693.  
  6694. AGADisclosureTriangle::AGADisclosureTriangle(Rect* bounds, Boolean automaticState)
  6695. : AGAObject(bounds)
  6696.     {
  6697.     // Construct as specified.
  6698.  
  6699.     mAutomaticState = automaticState;
  6700.     mIsDisclosed = kClosedState;
  6701.     }
  6702.  
  6703. AGADisclosureTriangle::~AGADisclosureTriangle()
  6704.     {
  6705.     }
  6706.  
  6707. void AGADisclosureTriangle::DrawObject()
  6708.     {
  6709.     // Draw the triangle in the current state.
  6710.  
  6711.     this->DrawTriangle(mIsDisclosed ? kDTDisclosed : kDTClosed);
  6712.     }
  6713.  
  6714. Boolean AGADisclosureTriangle::TrackMouse(Point mouseLocation)
  6715.     {
  6716.     // Let superclass handle tracking, and change our state
  6717.     // if we have automatic state change turned on.
  6718.  
  6719.     Boolean    wasItHit = AGAObject::TrackMouse(mouseLocation);
  6720.  
  6721.     if (wasItHit && mAutomaticState)
  6722.         this->SetStateAnimate(! mIsDisclosed);
  6723.  
  6724.     return wasItHit;
  6725.     }
  6726.  
  6727. Boolean AGADisclosureTriangle::GetState()
  6728.     {
  6729.     // Return the current state.
  6730.  
  6731.     return mIsDisclosed;
  6732.     }
  6733.  
  6734. void AGADisclosureTriangle::SetState(Boolean isDisclosed, Boolean redraw)
  6735.     {
  6736.     // Set the state and optionally redraw.
  6737.  
  6738.     if (isDisclosed != mIsDisclosed)
  6739.         {
  6740.         mIsDisclosed = isDisclosed;
  6741.         
  6742.         if (redraw)
  6743.             {
  6744.             this->DrawTriangle(mIsDisclosed ? kDTDisclosed : kDTClosed);
  6745.             }
  6746.         }
  6747.     }
  6748.  
  6749. void AGADisclosureTriangle::SetStateAnimate(Boolean isDisclosed)
  6750.     {
  6751.     // Set the state, but animate the triangle as it changes
  6752.     // to the new state.
  6753.  
  6754.     const SInt32 kAnimationDelay = 4;
  6755.  
  6756.     if (isDisclosed)
  6757.         {
  6758.         this->DrawTriangle(kDTPressedClosed);
  6759.         DelayFuture(kAnimationDelay);
  6760.  
  6761.         this->EraseBackground();
  6762.         this->DrawTriangle(kDTIntermediate);
  6763.         DelayFuture(kAnimationDelay);
  6764.  
  6765.         this->EraseBackground();
  6766.         this->DrawTriangle(kDTPressedDisclosed);
  6767.         DelayFuture(kAnimationDelay);
  6768.  
  6769.         this->EraseBackground();
  6770.         }
  6771.     else
  6772.         {
  6773.         this->DrawTriangle(kDTPressedDisclosed);
  6774.         DelayFuture(kAnimationDelay);
  6775.  
  6776.         this->EraseBackground();
  6777.         this->DrawTriangle(kDTIntermediate);
  6778.         DelayFuture(kAnimationDelay);
  6779.  
  6780.         this->EraseBackground();
  6781.         this->DrawTriangle(kDTPressedClosed);
  6782.         DelayFuture(kAnimationDelay);
  6783.  
  6784.         this->EraseBackground();
  6785.         }
  6786.     
  6787.     this->SetState(isDisclosed, kRedraw);
  6788.     }
  6789.  
  6790. void AGADisclosureTriangle::SetTrackingState(Boolean isIn)
  6791.     {
  6792.     // Draw the triangle pressed or unpressed as specified.
  6793.  
  6794.     DTAnimationState    state;
  6795.     
  6796.     if (isIn)
  6797.         state = mIsDisclosed ? kDTPressedDisclosed : kDTPressedClosed;
  6798.     else
  6799.         state = mIsDisclosed ? kDTDisclosed : kDTClosed;
  6800.  
  6801.     this->DrawTriangle(state);
  6802.     }
  6803.  
  6804. void AGADisclosureTriangle::DrawTriangle(DTAnimationState state)
  6805.     {
  6806.     CleansePen();
  6807.  
  6808.     // Draw the triangle at the specified animation frame.
  6809.  
  6810.     Point        fulcrum;
  6811.     Point        corners[3];
  6812.     
  6813.     ::SetPt(&fulcrum, mBounds.left + 5, mBounds.top + 5);
  6814.  
  6815.     switch (state)
  6816.         {
  6817.         case kDTClosed:
  6818.         case kDTPressedClosed:
  6819.             ::SetPt(&corners[0], fulcrum.h - 2, fulcrum.v - 5);
  6820.             ::SetPt(&corners[1], fulcrum.h + 3, fulcrum.v);
  6821.             ::SetPt(&corners[2], fulcrum.h - 2, fulcrum.v + 5);
  6822.             break;
  6823.         case kDTIntermediate:
  6824.             ::SetPt(&corners[0], fulcrum.h + 3, fulcrum.v - 5);
  6825.             ::SetPt(&corners[1], fulcrum.h + 3, fulcrum.v + 3);
  6826.             ::SetPt(&corners[2], fulcrum.h - 5, fulcrum.v + 3);
  6827.             break;
  6828.         case kDTPressedDisclosed:
  6829.         case kDTDisclosed:
  6830.             ::SetPt(&corners[0], fulcrum.h + 5, fulcrum.v - 2);
  6831.             ::SetPt(&corners[1], fulcrum.h, fulcrum.v + 3);
  6832.             ::SetPt(&corners[2], fulcrum.h - 5, fulcrum.v - 2);
  6833.             break;
  6834.         }
  6835.     
  6836.     // Little trick: tweak state so that disabled state (gray
  6837.     // fill) is handled by pressed case code below. We already set
  6838.     // the color so they only set pressed fill color if enabled.
  6839.     DTAnimationState    deepState = state;
  6840.     
  6841.     if (! mEnabled)
  6842.         {
  6843.         if (deepState == kDTClosed)
  6844.             deepState = kDTPressedClosed;
  6845.         else
  6846.             deepState = kDTPressedDisclosed;
  6847.         }
  6848.             
  6849.     GDIterator    iter;
  6850.     Boolean        deep;
  6851.  
  6852.     while (iter.More(deep))
  6853.         {
  6854.         if (deep)
  6855.             {
  6856.             if (mEnabled)
  6857.                 ::RGBForeColor(&gAGARamp[rB]);
  6858.             else
  6859.                 ::RGBForeColor(&gAGARamp[r5]);
  6860.  
  6861.             ::MoveTo(corners[0].h, corners[0].v);
  6862.             ::LineTo(corners[1].h, corners[1].v);
  6863.             ::LineTo(corners[2].h, corners[2].v);
  6864.             ::LineTo(corners[0].h, corners[0].v);
  6865.             
  6866.             switch (deepState)
  6867.                 {
  6868.                 case kDTClosed:
  6869.                     ::RGBForeColor(&gAGARamp[rA1]);
  6870.                     ::MoveTo(corners[0].h + 1, corners[0].v + 2);
  6871.                     ::Line(0, 6);
  6872.                     ::RGBForeColor(&gAGARamp[rA2]);
  6873.                     ::Line(1, -1);
  6874.                     ::Line(0, -4);
  6875.                     ::Line(1, 1);
  6876.                     ::Line(0, 1);
  6877.                     ::Move(1, 0);
  6878.                     ::RGBForeColor(&gAGARamp[rA3]);
  6879.                     ::Line(-2, 2);
  6880.  
  6881.                     ::RGBForeColor(&gAGARamp[r7]);
  6882.                     ::MoveTo(corners[2].h + 1, corners[2].v);
  6883.                     ::Line(4, -4);
  6884.                     ::RGBForeColor(&gAGARamp[r4]);
  6885.                     ::Move(1, 0);
  6886.                     ::Line(-5, 5);
  6887.                     break;
  6888.                 case kDTPressedClosed:
  6889.                     if (mEnabled)
  6890.                         ::RGBForeColor(&gAGARamp[rA4]);
  6891.  
  6892.                     ::MoveTo(corners[0].h + 1, corners[0].v + 2);
  6893.                     ::Line(0, 6);
  6894.                     ::Move(1, -1);
  6895.                     ::Line(0, -4);
  6896.                     ::Move(1, 1);
  6897.                     ::Line(0, 2);
  6898.                     ::Line(1, -1);
  6899.  
  6900.                     ::RGBForeColor(&gAGARamp[r2]);
  6901.                     ::MoveTo(corners[2].h + 1, corners[2].v);
  6902.                     ::Line(4, -4);
  6903.                     ::Move(1, 0);
  6904.                     ::Line(-5, 5);
  6905.                     break;
  6906.                 case kDTIntermediate:
  6907.                     ::RGBForeColor(&gAGARamp[rA4]);
  6908.                     ::MoveTo(corners[0].h - 1, corners[0].v + 2);
  6909.                     ::Line(-5, 5);
  6910.                     ::Move(1, 0);
  6911.                     ::Line(4, -4);
  6912.                     ::Move(0, 1);
  6913.                     ::Line(-3, 3);
  6914.                     ::Move(1, 0);
  6915.                     ::Line(2, -2);
  6916.                     ::Move(0, 1);
  6917.                     ::Line(-1, 1);
  6918.                     ::Line(1, 0);
  6919.                     break;
  6920.                 case kDTPressedDisclosed:
  6921.                     if (mEnabled)
  6922.                         ::RGBForeColor(&gAGARamp[rA4]);
  6923.  
  6924.                     ::MoveTo(corners[2].h + 2, corners[2].v + 1);
  6925.                     ::Line(6, 0);
  6926.                     ::Move(-1, 1);
  6927.                     ::Line(-4, 0);
  6928.                     ::Move(1, 1);
  6929.                     ::Line(2, 0);
  6930.                     ::Line(-1, 1);
  6931.  
  6932.                     ::RGBForeColor(&gAGARamp[r2]);
  6933.                     ::MoveTo(corners[0].h, corners[0].v + 1);
  6934.                     ::Line(-4, 4);
  6935.                     ::Move(0, 1);
  6936.                     ::Line(5, -5);
  6937.                     break;
  6938.                 case kDTDisclosed:
  6939.                     ::RGBForeColor(&gAGARamp[rA1]);
  6940.                     ::MoveTo(corners[2].h + 2, corners[2].v + 1);
  6941.                     ::Line(6, 0);
  6942.                     ::RGBForeColor(&gAGARamp[rA2]);
  6943.                     ::Line(-1, 1);
  6944.                     ::Line(-4, 0);
  6945.                     ::Line(1, 1);
  6946.                     ::Line(1, 0);
  6947.                     ::Move(0, 1);
  6948.                     ::RGBForeColor(&gAGARamp[rA3]);
  6949.                     ::Line(2, -2);
  6950.  
  6951.                     ::RGBForeColor(&gAGARamp[r7]);
  6952.                     ::MoveTo(corners[0].h, corners[0].v + 1);
  6953.                     ::Line(-4, 4);
  6954.                     ::RGBForeColor(&gAGARamp[r4]);
  6955.                     ::Move(0, 1);
  6956.                     ::Line(5, -5);
  6957.                     break;
  6958.                 }
  6959.             }
  6960.         else    // 1-bit
  6961.             {
  6962.             PolyHandle    theTriangle = ::OpenPoly();
  6963.  
  6964.             ::MoveTo(corners[0].h, corners[0].v);
  6965.             ::LineTo(corners[1].h, corners[1].v);
  6966.             ::LineTo(corners[2].h, corners[2].v);
  6967.             ::LineTo(corners[0].h, corners[0].v);
  6968.             
  6969.             ::ClosePoly();
  6970.             
  6971.             switch (state)
  6972.                 {
  6973.                 case kDTClosed:
  6974.                 case kDTDisclosed:
  6975.                     ::RGBForeColor(&gAGARamp[rW]);
  6976.                     ::PaintPoly(theTriangle);
  6977.                     ::RGBForeColor(&gAGARamp[rB]);
  6978.                     ::FramePoly(theTriangle);
  6979.  
  6980.                     if (! mEnabled)
  6981.                         {
  6982.                         ::PenPat(&qd.gray);
  6983.                         ::PenMode(patBic);
  6984.                         ::PaintRect(&mBounds);
  6985.  
  6986.                         ::PenNormal();
  6987.                         }
  6988.                     break;
  6989.                 case kDTPressedClosed:
  6990.                 case kDTIntermediate:
  6991.                 case kDTPressedDisclosed:
  6992.                     ::RGBForeColor(&gAGARamp[rB]);
  6993.                     ::PaintPoly(theTriangle);
  6994.                     break;
  6995.                 }
  6996.             
  6997.             ::KillPoly(theTriangle);
  6998.             ::PenNormal();
  6999.             }
  7000.         }
  7001.  
  7002.     CleansePen();
  7003.     }
  7004.  
  7005. void AGADisclosureTriangle::EraseBackground()
  7006.     {
  7007.     GDIterator    iter;
  7008.     Boolean        deep;
  7009.  
  7010.     while (iter.More(deep))
  7011.         {
  7012.         if (deep)
  7013.             ::RGBForeColor(&mBackgroundEraseColor);
  7014.         else
  7015.             ::RGBForeColor(&gAGARamp[rW]);
  7016.  
  7017.         ::PaintRect(&mBounds);
  7018.         }
  7019.     }
  7020.  
  7021. //
  7022. // AGAProgressIndicator ---------------------------------------------------------------
  7023. //
  7024. // This class implements a progress indicator that can be either
  7025. // determinate or indeterminate, and also can have a moving start
  7026. // value.
  7027. //
  7028.  
  7029. // We use an offscreen image for the indeterminate progress pattern.
  7030. AGAOffscreenImage*    AGAProgressIndicator::mgOffscreenIndeterminateProgressImage[kNumProgressPatterns];
  7031.  
  7032. // These are the color ramp indexes that are used to build the offscreen image.
  7033. SInt8                AGAProgressIndicator::kIndeterminateProgressImage[kNumProgressPatterns]
  7034.                                                                 [kProgressImageHeight]
  7035.                                                                     [kProgressImageWidth] =
  7036.         {
  7037.         {    // k1BitPattern
  7038.             {  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rW },
  7039.             {  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW,  rW,  rW,  rW,  rW },
  7040.             {  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW,  rW,  rW,  rW },
  7041.             {  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW,  rW,  rW },
  7042.             {  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW,  rW },
  7043.             {  rW,  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW,  rW },
  7044.             {  rW,  rW,  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW,  rW },
  7045.             {  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rW },
  7046.             {  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB,  rB },
  7047.             {  rB,  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rW,  rB,  rB,  rB,  rB,  rB,  rB,  rB },
  7048.         },
  7049.         {    // kDeepPattern
  7050.             {  rA,  rA,  rA,  rA,  rA,  rA,  rA,  rA, r10, r10, r10, r10, r10, r10, r10, r10 },
  7051.             {  r8, r10, r10, r10, r10, r10, r10, r10, r10,  r8,  r8,  r8,  r8,  r8,  r8,  r8 },
  7052.             {  r5,  r5,  r8,  r8,  r8,  r8,  r8,  r8,  r8,  r8,  r5,  r5,  r5,  r5,  r5,  r5 },
  7053.             {  r2,  r2,  r2,  r5,  r5,  r5,  r5,  r5,  r5,  r5,  r5,  r2,  r2,  r2,  r2,  r2 },
  7054.             {  rW,  rW,  rW,  rW,  r3,  r3,  r3,  r3,  r3,  r3,  r3,  r3,  rW,  rW,  rW,  rW },
  7055.             {  r2,  r2,  r2,  r2,  r2,  r5,  r5,  r5,  r5,  r5,  r5,  r5,  r5,  r2,  r2,  r2 },
  7056.             {  r4,  r4,  r4,  r4,  r4,  r4,  r8,  r8,  r8,  r8,  r8,  r8,  r8,  r8,  r4,  r4 },
  7057.             {  r6,  r6,  r6,  r6,  r6,  r6,  r6, r10, r10, r10, r10, r10, r10, r10, r10,  r6 },
  7058.             {  r8,  r8,  r8,  r8,  r8,  r8,  r8,  r8,  rA,  rA,  rA,  rA,  rA,  rA,  rA,  rA },
  7059.             { r12, r10, r10, r10, r10, r10, r10, r10, r10, r12, r12, r12, r12, r12, r12, r12 },
  7060.         },
  7061.     };
  7062.  
  7063. OSErr AGAProgressIndicator::AllocateProgressImages()
  7064.     {
  7065.     // Allocate the offscreen image for each radio button state.
  7066.  
  7067.     OSErr    result = noErr;
  7068.     Point    imageSize;
  7069.     
  7070.     imageSize.h = kProgressImageWidth;
  7071.     imageSize.v = kProgressImageHeight;
  7072.     
  7073.     for (UInt32 imageIndex = 0; imageIndex < kNumProgressPatterns; imageIndex++)
  7074.         {
  7075.         if (result == noErr)
  7076.             {
  7077.             mgOffscreenIndeterminateProgressImage[imageIndex] = new AGAOffscreenImage;
  7078.             
  7079.             result = mgOffscreenIndeterminateProgressImage[imageIndex]->CreateImageData(
  7080.                         imageSize,
  7081.                         &kIndeterminateProgressImage[imageIndex][0][0],
  7082.                         NULL);
  7083.             }
  7084.         }
  7085.         
  7086.     return result;
  7087.     }
  7088.  
  7089. void AGAProgressIndicator::DisposeProgressImages()
  7090.     {
  7091.     for (UInt32 imageIndex = 0; imageIndex < kNumProgressPatterns; imageIndex++)
  7092.         if (mgOffscreenIndeterminateProgressImage[imageIndex] != NULL)
  7093.             delete mgOffscreenIndeterminateProgressImage[imageIndex];
  7094.     }
  7095.  
  7096. AGAProgressIndicator::AGAProgressIndicator(Rect* bounds, SInt32 minimum, SInt32 maximum)
  7097. : AGAObject(bounds)
  7098.     {
  7099.     // Construct with default options.
  7100.     // (minimum == maximum) means indeterminate indicator.
  7101.  
  7102.     mMinimum = minimum;
  7103.     mMaximum = maximum;
  7104.     mValue = minimum;
  7105.     mOriginValue = minimum;
  7106.     mAnimationIndex = 0;
  7107.     }
  7108.  
  7109. AGAProgressIndicator::~AGAProgressIndicator()
  7110.     {
  7111.     }
  7112.  
  7113. void AGAProgressIndicator::DrawObject()
  7114.     {
  7115.     // Draw at current gauge value or next animation step.
  7116.  
  7117.     this->DrawFrame();
  7118.     
  7119.     if (mMinimum == mMaximum)
  7120.         this->DrawAnimationStep();
  7121.     else
  7122.         this->DrawGauge();
  7123.     }
  7124.  
  7125. SInt32 AGAProgressIndicator::GetValue()
  7126.     {
  7127.     // Return current value.
  7128.  
  7129.     return mValue;
  7130.     }
  7131.  
  7132. void AGAProgressIndicator::SetValue(SInt32 newValue, Boolean redraw)
  7133.     {
  7134.     // Set gauge value, optionally redraw.
  7135.  
  7136.     // Constrain: mMinimum <= mValue <= mMaximum
  7137.     newValue = MaxSInt32(mMinimum, MinSInt32(newValue, mMaximum));
  7138.     
  7139.     if (newValue != mValue)
  7140.         {
  7141.         mValue = newValue;
  7142.         
  7143.         if (redraw)
  7144.             this->DrawGauge();
  7145.         }
  7146.     }
  7147.  
  7148. void AGAProgressIndicator::Increment(SInt32 delta, Boolean redraw)
  7149.     {
  7150.     // Increment gauge value, optionally redraw.
  7151.  
  7152.     this->SetValue(delta + this->GetValue(), redraw);
  7153.     }
  7154.  
  7155. void AGAProgressIndicator::Animate()
  7156.     {
  7157.     // Draw the next animation step.
  7158.  
  7159.     mAnimationIndex = (mAnimationIndex + 1) % kNumProgressAnimationSteps;
  7160.     
  7161.     this->DrawAnimationStep();
  7162.     }
  7163.  
  7164. void AGAProgressIndicator::GetRange(SInt32* minimum, SInt32* maximum)
  7165.     {
  7166.     // Return the gauge value range.
  7167.  
  7168.     *minimum = mMinimum;
  7169.     *maximum = mMaximum;
  7170.     }
  7171.  
  7172. void AGAProgressIndicator::SetRange(SInt32 newMinimum, SInt32 newMaximum, Boolean redraw)
  7173.     {
  7174.     // Set the gauge value range, optionally redraw.
  7175.     // (minimum == maximum) means indeterminate indicator.
  7176.  
  7177.     if (mOriginValue == mMinimum)
  7178.         mOriginValue = newMinimum;
  7179.  
  7180.     mMinimum = newMinimum;
  7181.     mMaximum = MaxSInt32(newMinimum, newMaximum);
  7182.     
  7183.     if (redraw)
  7184.         this->DrawObject();
  7185.     }
  7186.  
  7187. SInt32 AGAProgressIndicator::GetOriginValue()
  7188.     {
  7189.     // Return the optional gauge origin value.
  7190.  
  7191.     return mOriginValue;
  7192.     }
  7193.  
  7194. void AGAProgressIndicator::SetOriginValue(SInt32 newValue, Boolean redraw)
  7195.     {
  7196.     // Set the optional gauge origin value.
  7197.  
  7198.     // Constrain: mMinimum <= mOriginValue <= mValue
  7199.     newValue = MaxSInt32(mMinimum, MinSInt32(newValue, mValue));
  7200.  
  7201.     if (newValue != mOriginValue)
  7202.         {
  7203.         mOriginValue = newValue;
  7204.         
  7205.         if (redraw)
  7206.             this->DrawObject();
  7207.         }
  7208.     }
  7209.  
  7210. void AGAProgressIndicator::DrawFrame()
  7211.     {
  7212.     CleansePen();
  7213.  
  7214.     // Draw the constant frame around the indicator.
  7215.     Rect    r = mBounds;
  7216.     
  7217.     r.bottom = r.top + kProgressHeight;
  7218.     
  7219.  
  7220.     GDIterator    iter;
  7221.     Boolean        deep;
  7222.  
  7223.     while (iter.More(deep))
  7224.         {
  7225.         if (deep)
  7226.             {
  7227.             ::RGBForeColor(&gAGARamp[r5]);
  7228.             ::MoveTo(r.left, r.bottom - 2);
  7229.             ::LineTo(r.left, r.top);
  7230.             ::LineTo(r.right - 2, r.top);
  7231.             
  7232.             ::RGBForeColor(&gAGARamp[rW]);
  7233.             ::MoveTo(r.left + 1, r.bottom - 1);
  7234.             ::LineTo(r.right - 1, r.bottom - 1);
  7235.             ::LineTo(r.right - 1, r.top + 1);
  7236.             }
  7237.         
  7238.         ::InsetRect(&r, 1, 1);
  7239.         ::RGBForeColor(&gAGARamp[rB]);
  7240.         ::FrameRect(&r);
  7241.         ::InsetRect(&r, -1, -1);
  7242.         }
  7243.  
  7244.     CleansePen();
  7245.     }
  7246.  
  7247. void AGAProgressIndicator::DrawAnimationStep()
  7248.     {
  7249.     CleansePen();
  7250.  
  7251.     // Draw the indeterminate progress indicator at the
  7252.     // current animation step.
  7253.  
  7254.     const UInt32 kNumRows = 10;
  7255.  
  7256.     Rect    r = mBounds;
  7257.     SInt16    patternHOrigin;
  7258.     
  7259.     r.bottom = r.top + kProgressHeight;
  7260.     ::InsetRect(&r, 2, 2);
  7261.     
  7262.     //
  7263.     // Move the pen leftward so the pattern is offset for
  7264.     // the current animation step. This will mean we need
  7265.     // to explicitly clip to our gauge area, since our pattern
  7266.     // origin is outside it.
  7267.     //
  7268.  
  7269.     patternHOrigin = r.left - 32 + ((16 / kNumProgressAnimationSteps) * mAnimationIndex);
  7270.     
  7271.     RgnHandle    savedClip = ::NewRgn();
  7272.     ::GetClip(savedClip);
  7273.     
  7274.     AGAClipFurther(&r);
  7275.     
  7276.     r.left = patternHOrigin;
  7277.  
  7278.     {
  7279.     GDIterator    iter;
  7280.     Boolean        deep;
  7281.  
  7282.     while (iter.More(deep))
  7283.         {
  7284.         if (deep)
  7285.             mgOffscreenIndeterminateProgressImage[kDeepPattern]->DrawPattern(&r);
  7286.         else
  7287.             mgOffscreenIndeterminateProgressImage[k1BitPattern]->DrawPattern(&r);
  7288.         }
  7289.     }    // force GDIterator clip to clean up now, not after we set savedClip!
  7290.  
  7291.     ::SetClip(savedClip);
  7292.     ::DisposeRgn(savedClip);
  7293.  
  7294.     CleansePen();
  7295.     }
  7296.  
  7297. void AGAProgressIndicator::DrawGauge()
  7298.     {
  7299.     // Draw the determinate progress indicator.
  7300.  
  7301.     if (mOriginValue != mMinimum)
  7302.         this->DrawOriginArea();
  7303.     
  7304.     this->DrawProgressArea();
  7305.     this->DrawRemainderArea();
  7306.     }
  7307.  
  7308. void AGAProgressIndicator::DrawOriginArea()
  7309.     {
  7310.     // Draw the empty track between the minimum value
  7311.     // and the origin value.
  7312.  
  7313.     Rect    frame;
  7314.     
  7315.     if (this->GetOriginFrame(&frame))
  7316.         {
  7317.         GDIterator    iter;
  7318.         Boolean        deep;
  7319.  
  7320.         while (iter.More(deep))
  7321.             {
  7322.             Rect    r = frame;
  7323.  
  7324.             if (deep)
  7325.                 {
  7326.                 SInt16    width = r.right - r.left;
  7327.                 
  7328.                 if (width >= 0)
  7329.                     {
  7330.                     ::RGBForeColor(&gAGARamp[rB]);
  7331.                     ::MoveTo(r.right, r.top);
  7332.                     ::LineTo(r.right, r.bottom - 1);
  7333.                     }
  7334.  
  7335.                 if (width > 0)
  7336.                     {
  7337.                     ::RGBForeColor(&gAGARamp[r10]);
  7338.                     ::MoveTo(r.left, r.top);
  7339.                     ::LineTo(r.left, r.bottom - 1);
  7340.                     }
  7341.                 
  7342.                 if (width > 1)
  7343.                     {
  7344.                     ::RGBForeColor(&gAGARamp[r4]);
  7345.                     ::MoveTo(r.right - 1, r.top);
  7346.                     ::Line(0, 1);
  7347.                     ::RGBForeColor(&gAGARamp[r2]);
  7348.                     ::LineTo(r.right - 1, r.bottom - 1);
  7349.                     }
  7350.                 
  7351.                 if (width > 2)
  7352.                     {
  7353.                     ::RGBForeColor(&gAGARamp[r7]);
  7354.                     ::MoveTo(r.left + 1, r.top);
  7355.                     ::LineTo(r.left + 1, r.bottom - 1);
  7356.                     }
  7357.                 
  7358.                 if (width > 3)
  7359.                     {
  7360.                     ::RGBForeColor(&gAGARamp[r2]);
  7361.                     ::MoveTo(r.left + 2, r.bottom - 1);
  7362.                     ::LineTo(r.right - 1, r.bottom - 1);
  7363.  
  7364.                     ::RGBForeColor(&gAGARamp[r7]);
  7365.                     ::MoveTo(r.left + 2, r.top);
  7366.                     ::LineTo(r.right - 2, r.top);
  7367.  
  7368.                     ::RGBForeColor(&gAGARamp[r4]);
  7369.                     r.left += 2;
  7370.                     r.top++;
  7371.                     r.bottom--;
  7372.                     r.right--;
  7373.                     ::PaintRect(&r);
  7374.                     }
  7375.                 }
  7376.             else    // 1-bit
  7377.                 {
  7378.                 ::RGBForeColor(&gAGARamp[rW]);
  7379.                 ::PaintRect(&r);
  7380.                 }
  7381.             }
  7382.         }
  7383.  
  7384.     CleansePen();
  7385.     }
  7386.  
  7387. void AGAProgressIndicator::DrawProgressArea()
  7388.     {
  7389.     CleansePen();
  7390.  
  7391.     // Draw the filled progress gauge area between
  7392.     // the origin and the current value.
  7393.  
  7394.     Rect    frame;
  7395.     
  7396.     if (this->GetProgressFrame(&frame))
  7397.         {
  7398.         GDIterator    iter;
  7399.         Boolean        deep;
  7400.  
  7401.         while (iter.More(deep))
  7402.             {
  7403.             Rect    r = frame;
  7404.  
  7405.             if (deep)
  7406.                 {
  7407.                 SInt16    width = r.right - r.left;
  7408.  
  7409.                 //
  7410.                 // Because the endcaps of the gauge are shaded,
  7411.                 // we need to carefully draw the ends horizontal
  7412.                 // pixel by pixel, bailing out if there is not
  7413.                 // enough width to accomodate the endcaps and the
  7414.                 // midsection.
  7415.                 //
  7416.  
  7417.                 if (width > 0)
  7418.                     {
  7419.                     ::RGBForeColor(&gAGARamp[rB]);
  7420.                     ::MoveTo(r.right - 1, r.top);
  7421.                     ::LineTo(r.right - 1, r.bottom - 1);
  7422.                     }
  7423.  
  7424.                 if (width > 1)
  7425.                     {
  7426.                     ::RGBForeColor(&gAGARamp[r8]);
  7427.                     ::MoveTo(r.left, r.top);
  7428.                     ::LineTo(r.left, r.bottom - 1);
  7429.                     }
  7430.  
  7431.                 if (width > 2)
  7432.                     {
  7433.                     ::RGBForeColor(&gAGARamp[r10]);
  7434.                     ::MoveTo(r.right - 2, r.top);
  7435.                     ::Line(0, 1);
  7436.                     ::RGBForeColor(&gAGARamp[r12]);
  7437.                     ::LineTo(r.right - 2, r.bottom - 1);
  7438.                     }
  7439.  
  7440.                 if (width > 3)
  7441.                     {
  7442.                     ::RGBForeColor(&gAGARamp[r8]);
  7443.                     ::MoveTo(r.left + 1, r.top);
  7444.                     ::Line(0, 1);
  7445.                     ::RGBForeColor(&gAGARamp[r5]);
  7446.                     ::Line(0, 1);
  7447.                     ::RGBForeColor(&gAGARamp[r3]);
  7448.                     ::Line(0, 1);
  7449.                     ::RGBForeColor(&gAGARamp[r1]);
  7450.                     ::Line(0, 3);
  7451.                     ::RGBForeColor(&gAGARamp[r3]);
  7452.                     ::Line(0, 1);
  7453.                     ::RGBForeColor(&gAGARamp[r5]);
  7454.                     ::Line(0, 1);
  7455.                     ::RGBForeColor(&gAGARamp[r8]);
  7456.                     ::Line(0, 1);
  7457.                     ::RGBForeColor(&gAGARamp[r10]);
  7458.                     ::Line(0, 0);
  7459.                     }
  7460.  
  7461.                 if (width > 4)
  7462.                     {
  7463.                     ::RGBForeColor(&gAGARamp[r10]);
  7464.                     ::MoveTo(r.right - 3, r.top);
  7465.                     ::Line(0, 1);
  7466.                     ::RGBForeColor(&gAGARamp[r8]);
  7467.                     ::Line(0, 1);
  7468.                     ::RGBForeColor(&gAGARamp[r10]);
  7469.                     ::LineTo(r.right - 3, r.bottom - 1);
  7470.                     ::RGBForeColor(&gAGARamp[r12]);
  7471.                     ::Line(0, 0);
  7472.                     }
  7473.  
  7474.                 if (width > 5)
  7475.                     {
  7476.                     ::RGBForeColor(&gAGARamp[r10]);
  7477.                     ::MoveTo(r.right - 4, r.top);
  7478.                     ::Line(0, 1);
  7479.                     ::RGBForeColor(&gAGARamp[r8]);
  7480.                     ::Line(0, 1);
  7481.                     ::RGBForeColor(&gAGARamp[r5]);
  7482.                     ::Line(0, 1);
  7483.                     ::RGBForeColor(&gAGARamp[r3]);
  7484.                     ::Line(0, 3);
  7485.                     ::RGBForeColor(&gAGARamp[r5]);
  7486.                     ::Line(0, 1);
  7487.                     ::RGBForeColor(&gAGARamp[r8]);
  7488.                     ::Line(0, 1);
  7489.                     ::RGBForeColor(&gAGARamp[r10]);
  7490.                     ::Line(0, 1);
  7491.                     ::RGBForeColor(&gAGARamp[r12]);
  7492.                     ::Line(0, 0);
  7493.                     }
  7494.  
  7495.                 if (width > 6)
  7496.                     {
  7497.                     SInt16    distance = width - 7;
  7498.                     
  7499.                     ::RGBForeColor(&gAGARamp[r10]);
  7500.                     ::MoveTo(r.left + 2, r.top);
  7501.                     ::Line(distance, 0);
  7502.                     ::RGBForeColor(&gAGARamp[r8]);
  7503.                     ::MoveTo(r.left + 2, r.top + 1);
  7504.                     ::Line(distance, 0);
  7505.                     ::RGBForeColor(&gAGARamp[r5]);
  7506.                     ::MoveTo(r.left + 2, r.top + 2);
  7507.                     ::Line(distance, 0);
  7508.                     ::RGBForeColor(&gAGARamp[r3]);
  7509.                     ::MoveTo(r.left + 2, r.top + 3);
  7510.                     ::Line(distance, 0);
  7511.                     ::RGBForeColor(&gAGARamp[r1]);
  7512.                     ::MoveTo(r.left + 2, r.top + 4);
  7513.                     ::Line(distance, 0);
  7514.                     ::RGBForeColor(&gAGARamp[r3]);
  7515.                     ::MoveTo(r.left + 2, r.top + 5);
  7516.                     ::Line(distance, 0);
  7517.                     ::RGBForeColor(&gAGARamp[r5]);
  7518.                     ::MoveTo(r.left + 2, r.top + 6);
  7519.                     ::Line(distance, 0);
  7520.                     ::RGBForeColor(&gAGARamp[r8]);
  7521.                     ::MoveTo(r.left + 2, r.top + 7);
  7522.                     ::Line(distance, 0);
  7523.                     ::RGBForeColor(&gAGARamp[r10]);
  7524.                     ::MoveTo(r.left + 2, r.top + 8);
  7525.                     ::Line(distance, 0);
  7526.                     ::RGBForeColor(&gAGARamp[r12]);
  7527.                     ::MoveTo(r.left + 2, r.top + 9);
  7528.                     ::Line(distance, 0);
  7529.                     }
  7530.                 }
  7531.             else    // 1-bit
  7532.                 {
  7533.                 ::RGBForeColor(&gAGARamp[rB]);
  7534.                 ::PaintRect(&r);
  7535.                 }
  7536.             }
  7537.         }
  7538.  
  7539.     CleansePen();
  7540.     }
  7541.  
  7542. void AGAProgressIndicator::DrawRemainderArea()
  7543.     {
  7544.     CleansePen();
  7545.  
  7546.     // Draw the empty track area between the current
  7547.     // gauge value and the maximum.
  7548.  
  7549.     Rect    frame;
  7550.     
  7551.     if (this->GetRemainderFrame(&frame))
  7552.         {
  7553.         GDIterator    iter;
  7554.         Boolean        deep;
  7555.  
  7556.         while (iter.More(deep))
  7557.             {
  7558.             Rect    r = frame;
  7559.  
  7560.             if (deep)
  7561.                 {
  7562.                 SInt16    width = r.right - r.left;
  7563.                 
  7564.                 if (width > 0)
  7565.                     {
  7566.                     ::RGBForeColor(&gAGARamp[r10]);
  7567.                     ::MoveTo(r.left, r.top);
  7568.                     ::LineTo(r.left, r.bottom - 1);
  7569.                     }
  7570.                 
  7571.                 if (width > 1)
  7572.                     {
  7573.                     ::RGBForeColor(&gAGARamp[r4]);
  7574.                     ::MoveTo(r.right - 1, r.top);
  7575.                     ::Line(0, 1);
  7576.                     ::RGBForeColor(&gAGARamp[r2]);
  7577.                     ::LineTo(r.right - 1, r.bottom - 1);
  7578.                     }
  7579.                 
  7580.                 if (width > 2)
  7581.                     {
  7582.                     ::RGBForeColor(&gAGARamp[r7]);
  7583.                     ::MoveTo(r.left + 1, r.top);
  7584.                     ::LineTo(r.left + 1, r.bottom - 1);
  7585.                     }
  7586.                 
  7587.                 if (width > 3)
  7588.                     {
  7589.                     ::RGBForeColor(&gAGARamp[r2]);
  7590.                     ::MoveTo(r.left + 2, r.bottom - 1);
  7591.                     ::LineTo(r.right - 1, r.bottom - 1);
  7592.  
  7593.                     ::RGBForeColor(&gAGARamp[r7]);
  7594.                     ::MoveTo(r.left + 2, r.top);
  7595.                     ::LineTo(r.right - 2, r.top);
  7596.  
  7597.                     ::RGBForeColor(&gAGARamp[r4]);
  7598.                     r.left += 2;
  7599.                     r.top++;
  7600.                     r.bottom--;
  7601.                     r.right--;
  7602.                     ::PaintRect(&r);
  7603.                     }
  7604.                 }
  7605.             else    // 1-bit
  7606.                 {
  7607.                 ::RGBForeColor(&gAGARamp[rW]);
  7608.                 ::PaintRect(&r);
  7609.                 }
  7610.             }
  7611.         }
  7612.  
  7613.     CleansePen();
  7614.     }
  7615.  
  7616. Boolean AGAProgressIndicator::GetOriginFrame(Rect* originFrame)
  7617.     {
  7618.     // Return true (and the area) if there is an area
  7619.     // to be drawn for the empty origin part of the track.
  7620.  
  7621.     Boolean    isNeeded = FALSE;
  7622.     
  7623.     if (mOriginValue != mMinimum)
  7624.         {
  7625.         isNeeded = TRUE;
  7626.  
  7627.         this->GetRangeFrame(mMinimum, mOriginValue, originFrame);
  7628.         
  7629.         if (mOriginValue != mMaximum)
  7630.             originFrame->right--;
  7631.         }
  7632.  
  7633.     return isNeeded;
  7634.     }
  7635.  
  7636. Boolean AGAProgressIndicator::GetProgressFrame(Rect* progressFrame)
  7637.     {
  7638.     // Return true (and the area) if there is an area
  7639.     // to be drawn for the progress section of the gauge.
  7640.  
  7641.     Boolean    isNeeded = FALSE;
  7642.     
  7643.     if (mValue != mOriginValue)
  7644.         {
  7645.         isNeeded = TRUE;
  7646.  
  7647.         this->GetRangeFrame(mOriginValue, mValue, progressFrame);
  7648.         
  7649.         if (mValue == mMaximum)
  7650.             progressFrame->right++;
  7651.         }
  7652.  
  7653.     return isNeeded;
  7654.     }
  7655.  
  7656. Boolean AGAProgressIndicator::GetRemainderFrame(Rect* remainderFrame)
  7657.     {
  7658.     // Return true (and the area) if there is an area
  7659.     // to be drawn for the uncompleted gauge remainder area.
  7660.  
  7661.     Boolean    isNeeded = FALSE;
  7662.     
  7663.     if (mMaximum != mValue)
  7664.         {
  7665.         isNeeded = TRUE;
  7666.  
  7667.         this->GetRangeFrame(mValue, mMaximum, remainderFrame);
  7668.         }
  7669.  
  7670.     return isNeeded;
  7671.     }
  7672.  
  7673. void AGAProgressIndicator::GetRangeFrame(SInt32 startValue, SInt32 endValue, Rect* rangeFrame)
  7674.     {
  7675.     // Return the rectangle that the indicator draws in,
  7676.     // which does not include the constant border frame area.
  7677.  
  7678.     *rangeFrame = mBounds;
  7679.     rangeFrame->bottom = rangeFrame->top + kProgressHeight;
  7680.     
  7681.     ::InsetRect(rangeFrame, 2, 2);
  7682.  
  7683.     SInt32    divisor = mMaximum - mMinimum;
  7684.     
  7685.     if (divisor != 0)    // avoid divide by zero
  7686.         {
  7687.         SInt32    totalWidth = rangeFrame->right - rangeFrame->left;
  7688.         float    startFraction = ((float) (startValue - mMinimum)) / divisor;
  7689.         float    endFraction = ((float) (endValue - mMinimum)) / divisor;
  7690.  
  7691.         rangeFrame->right = rangeFrame->left + (endFraction * totalWidth);
  7692.         rangeFrame->left = rangeFrame->left + (startFraction * totalWidth);
  7693.         }
  7694.     }
  7695.  
  7696. //
  7697. // AGASeparator ---------------------------------------------------------------
  7698. //
  7699. // This class draws a separator line. It knowns whether it's horizontal or
  7700. // vertical based on the larger dimension.
  7701. //
  7702.  
  7703. AGASeparator::AGASeparator(Rect* bounds)
  7704. : AGAObject(bounds)
  7705.     {
  7706.     // Call superclass constructor.
  7707.     }
  7708.  
  7709. AGASeparator::~AGASeparator()
  7710.     {
  7711.     }
  7712.  
  7713. void AGASeparator::DrawObject()
  7714.     {
  7715.     CleansePen();
  7716.  
  7717.     // Draw the separator along the leading edge in
  7718.     // its longest dimension.
  7719.  
  7720.     Boolean    isHorizontal = ((mBounds.right - mBounds.left) > (mBounds.bottom - mBounds.top));
  7721.  
  7722.     GDIterator    iter;
  7723.     Boolean        deep;
  7724.  
  7725.     while (iter.More(deep))
  7726.         {
  7727.         if (deep)
  7728.             ::RGBForeColor(&gAGARamp[r7]);
  7729.         else
  7730.             {
  7731.             ::RGBForeColor(&gAGARamp[rB]);
  7732.             ::PenPat(&qd.gray);
  7733.             }
  7734.  
  7735.         ::MoveTo(mBounds.left, mBounds.top);
  7736.         
  7737.         if (isHorizontal)
  7738.             ::LineTo(mBounds.right - 2, mBounds.top);
  7739.         else
  7740.             ::LineTo(mBounds.left, mBounds.bottom - 2);
  7741.  
  7742.         if (deep)
  7743.             {
  7744.             ::RGBForeColor(&gAGARamp[rW]);
  7745.             ::MoveTo(mBounds.left + 1, mBounds.top + 1);
  7746.             
  7747.             if (isHorizontal)
  7748.                 ::LineTo(mBounds.right - 1, mBounds.top + 1);
  7749.             else
  7750.                 ::LineTo(mBounds.left + 1, mBounds.bottom - 1);
  7751.             }
  7752.         else
  7753.             ::PenPat(&qd.black);
  7754.         }
  7755.  
  7756.     CleansePen();
  7757.     }
  7758.  
  7759. //
  7760. // AGAGroupBox ---------------------------------------------------------------
  7761. //
  7762. // This class draws primary and secondary group boxes, with optional
  7763. // title label or title gap for a separate control.
  7764. //
  7765.  
  7766. AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType)
  7767. : AGAObject(bounds)
  7768.     {
  7769.     // Construct without a title or gap.
  7770.  
  7771.     mIsPrimaryBox = groupBoxType;
  7772.     mTitleGap = 0;
  7773.     mTitle[0] = 0;
  7774.     mTextStyle = textStyle;
  7775.     }
  7776.  
  7777. AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, SInt16 titleGap)
  7778. : AGAObject(bounds)
  7779.     {
  7780.     // Construct with specified gap.
  7781.  
  7782.     mIsPrimaryBox = groupBoxType;
  7783.     mTitleGap = titleGap;
  7784.     mTitle[0] = 0;
  7785.     mTextStyle = textStyle;
  7786.     }
  7787.  
  7788. AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, StringPtr titleString)
  7789. : AGAObject(bounds)
  7790.     {
  7791.     // Construct with specified title.
  7792.  
  7793.     mIsPrimaryBox = groupBoxType;
  7794.     mTitleGap = 0;
  7795.     PLstrcpy(mTitle, titleString);
  7796.     mTextStyle = textStyle;
  7797.     }
  7798.  
  7799. AGAGroupBox::AGAGroupBox(Rect* bounds, const AGATextStyle& textStyle, Boolean groupBoxType, SInt16 titleStringListResourceID, SInt16 titleStringIndex)
  7800. : AGAObject(bounds)
  7801.     {
  7802.     // Construct by getting title from specified resource.
  7803.  
  7804.     mIsPrimaryBox = groupBoxType;
  7805.     mTitleGap = 0;
  7806.     ::GetIndString(mTitle, titleStringListResourceID, titleStringIndex);
  7807.     mTextStyle = textStyle;
  7808.     }
  7809.  
  7810. AGAGroupBox::~AGAGroupBox()
  7811.     {
  7812.     }
  7813.  
  7814. void AGAGroupBox::SetTitleGap(SInt16 titleGap)
  7815.     {
  7816.     // Set the width of the title gap that will be left blank.
  7817.  
  7818.     mTitleGap = titleGap;
  7819.     }
  7820.  
  7821. void AGAGroupBox::SetTitle(StringPtr newTitle, Boolean redraw)
  7822.     {
  7823.     // Set the title, optionally redraw.
  7824.  
  7825.     PLstrcpy(mTitle, newTitle);
  7826.  
  7827.     if (redraw)
  7828.         this->DrawObject();
  7829.     }
  7830.  
  7831. void AGAGroupBox::DrawObject()
  7832.     {
  7833.     CleansePen();
  7834.  
  7835.     // Draw the group box.
  7836.  
  7837.     Rect        r = mBounds;
  7838.     SInt16        titleGap = 0;
  7839.     SInt16        topIndent = 0;
  7840.     FontInfo    fontInfo;
  7841.  
  7842.     if (mTitle[0] != 0)
  7843.         {
  7844.         ::TextFont(0);
  7845.         ::TextSize(0);
  7846.         ::TextFace(0);
  7847.         ::GetFontInfo(&fontInfo);
  7848.         
  7849.         topIndent = fontInfo.ascent;    // text baseline should be at frame top
  7850.         
  7851.         titleGap = 5 + ::StringWidth(mTitle);
  7852.         }
  7853.     else
  7854.         titleGap = mTitleGap;
  7855.  
  7856.     if (mIsPrimaryBox)
  7857.         this->DrawPrimaryFrame(topIndent, titleGap);
  7858.     else
  7859.         this->DrawSecondaryFrame(topIndent, titleGap);
  7860.  
  7861.     if (mTitle[0] != 0)
  7862.         {
  7863.         Rect    titleRect;
  7864.         
  7865.         titleRect.left = r.left + 14;
  7866.         titleRect.top = r.top + 2;
  7867.         titleRect.right = titleRect.left + titleGap;
  7868.         titleRect.bottom = titleRect.top + fontInfo.ascent + fontInfo.descent;
  7869.  
  7870.         GDIterator    iter;
  7871.         Boolean        deep;
  7872.  
  7873.         while (iter.More(deep))
  7874.             AGAStringOut(mTitle, &titleRect, kNoTruncation, teFlushDefault, mEnabled ? kNormalOutput : kDisabledOutput, deep, mTextStyle);
  7875.         }
  7876.  
  7877.     CleansePen();
  7878.     }
  7879.  
  7880. void AGAGroupBox::DrawPrimaryFrame(SInt16 topIndent, SInt16 gapSize)
  7881.     {
  7882.     // Draw the group box as a primary group.
  7883.  
  7884.     Rect    r = mBounds;
  7885.     
  7886.     r.top += topIndent;
  7887.  
  7888.     GDIterator    iter;
  7889.     Boolean        deep;
  7890.  
  7891.     while (iter.More(deep))
  7892.         {
  7893.         if (deep)
  7894.             {
  7895.             if (mEnabled)
  7896.                 ::RGBForeColor(&gAGARamp[r7]);
  7897.             else
  7898.                 ::RGBForeColor(&gAGARamp[r4]);
  7899.             }
  7900.         else
  7901.             {
  7902.             ::RGBForeColor(&gAGARamp[rB]);
  7903.             
  7904.             if (! mEnabled)
  7905.                 ::PenPat(&qd.gray);
  7906.             }
  7907.  
  7908.         ::MoveTo(r.right - 2, r.top);
  7909.         ::LineTo(r.right - 2, r.bottom - 2);
  7910.         ::LineTo(r.left, r.bottom - 2);
  7911.         ::LineTo(r.left, r.top);
  7912.         ::Line(10, 0);
  7913.         ::Move(gapSize, 0);
  7914.         ::LineTo(r.right - 2, r.top);
  7915.         
  7916.         if (deep)
  7917.             {
  7918.             if (mEnabled)
  7919.                 ::RGBForeColor(&gAGARamp[rW]);
  7920.             else
  7921.                 ::RGBForeColor(&gAGARamp[r1]);
  7922.  
  7923.             ::MoveTo(r.right - 1, r.top);
  7924.             ::LineTo(r.right - 1, r.bottom - 1);
  7925.             ::LineTo(r.left, r.bottom - 1);
  7926.             ::MoveTo(r.left + 1, r.bottom - 3);
  7927.             ::LineTo(r.left + 1, r.top + 1);
  7928.             ::Line(9, 0);
  7929.             ::Move(gapSize, 0);
  7930.             ::LineTo(r.right - 3, r.top + 1);
  7931.             }
  7932.         else
  7933.             ::PenPat(&qd.black);
  7934.         }
  7935.     }
  7936.  
  7937. void AGAGroupBox::DrawSecondaryFrame(SInt16 topIndent, SInt16 gapSize)
  7938.     {
  7939.     // Draw the group box as a secondary group.
  7940.  
  7941.     Rect    r = mBounds;
  7942.     
  7943.     r.top += topIndent;
  7944.  
  7945.     GDIterator    iter;
  7946.     Boolean        deep;
  7947.  
  7948.     while (iter.More(deep))
  7949.         {
  7950.         if (deep)
  7951.             {
  7952.             if (mEnabled)
  7953.                 ::RGBForeColor(&gAGARamp[rW]);
  7954.             else
  7955.                 ::RGBForeColor(&gAGARamp[r1]);
  7956.  
  7957.             ::MoveTo(r.right - 1, r.top + 1);
  7958.             ::LineTo(r.right - 1, r.bottom - 1);
  7959.             ::LineTo(r.left + 1, r.bottom - 1);
  7960.  
  7961.             if (mEnabled)
  7962.                 ::RGBForeColor(&gAGARamp[r7]);
  7963.             else
  7964.                 ::RGBForeColor(&gAGARamp[r4]);
  7965.  
  7966.             ::MoveTo(r.left, r.bottom - 2);
  7967.             ::LineTo(r.left, r.top);
  7968.             ::Line(10, 0);
  7969.             ::Move(gapSize, 0);
  7970.             ::LineTo(r.right - 2, r.top);
  7971.             }
  7972.         else
  7973.             {
  7974.             ::RGBForeColor(&gAGARamp[rB]);
  7975.             
  7976.             if (! mEnabled)
  7977.                 ::PenPat(&qd.gray);
  7978.  
  7979.             ::MoveTo(r.right - 2, r.top);
  7980.             ::LineTo(r.right - 2, r.bottom - 2);
  7981.             ::LineTo(r.left, r.bottom - 2);
  7982.             ::LineTo(r.left, r.top);
  7983.             ::Line(10, 0);
  7984.             ::Move(gapSize, 0);
  7985.             ::LineTo(r.right - 2, r.top);
  7986.             
  7987.             if (! mEnabled)
  7988.                 ::PenPat(&qd.black);
  7989.             }
  7990.         }
  7991.     }
  7992.  
  7993. //
  7994. // AGAStringOut --------------------------------------------------------
  7995. //
  7996. // This is the routine we use for all of our text output.
  7997. //
  7998.  
  7999. void AGAStringOut(StringPtr aString,
  8000.                     Rect* centeringFrame,
  8001.                     SInt32 truncation,
  8002.                     SInt32 justification,
  8003.                     AGAStringOutColor outColor,
  8004.                     Boolean deep,
  8005.                     const AGATextStyle& textStyle)
  8006.     {
  8007.     Str255        outputString;
  8008.     FontInfo    fontInfo;
  8009.     SInt16        frameWidth = centeringFrame->right - centeringFrame->left;
  8010.     SInt16        frameHeight = centeringFrame->bottom - centeringFrame->top;
  8011.     Point        penOrigin;
  8012.     Boolean        setColor = TRUE;
  8013.     UInt8        colorIndex;
  8014.     
  8015.     textStyle.PrepareForDrawing();
  8016.     ::GetFontInfo(&fontInfo);
  8017.  
  8018.     switch (outColor)
  8019.         {
  8020.         case kNormalOutput:
  8021.             colorIndex = rB;
  8022.             break;
  8023.         case kDisabledOutput:
  8024.             if (deep)
  8025.                 colorIndex = r7;
  8026.             else
  8027.                 colorIndex = rB;
  8028.             break;
  8029.         case kInverseOutput:
  8030.             colorIndex = rW;
  8031.             break;
  8032.         case kUseCurrentColor:
  8033.             setColor = FALSE;
  8034.             break;
  8035.         }
  8036.  
  8037.     if (setColor)
  8038.         ::RGBForeColor(&gAGARamp[colorIndex]);
  8039.     
  8040.     PLstrcpy(outputString, aString);
  8041.     
  8042.     // Truncate the string if it does not fit the width of the frame.
  8043.     if (truncation != kNoTruncation)
  8044.         {
  8045.         // If the string would be truncated at the current
  8046.         // font settings, try again with condensed text.
  8047.         if (::TruncString(frameWidth, outputString, truncation) == truncated)
  8048.             {
  8049.             PLstrcpy(outputString, aString);
  8050.             ::TextFace(condense);
  8051.             (void) ::TruncString(frameWidth, outputString, truncation);
  8052.             }
  8053.         }
  8054.     
  8055.     // Center the text vertically. Pen goes at baseline of
  8056.     // text, i.e. between the ascent and descent.
  8057.     penOrigin.v = centeringFrame->top + (frameHeight / 2) + ((fontInfo.ascent + fontInfo.descent) / 2) - fontInfo.descent;
  8058.     
  8059.     // Position the text horizontally left, centered, or right, based
  8060.     // on the specified justification and the system script direction.
  8061.     switch (RuntimeJustify(justification))
  8062.         {
  8063.         case teCenter:
  8064.             penOrigin.h = centeringFrame->left + (frameWidth / 2) - (::StringWidth(outputString) / 2);
  8065.             break;
  8066.         case teFlushRight:
  8067.             penOrigin.h = centeringFrame->right - ::StringWidth(outputString);
  8068.             break;
  8069.         default: //case teFlushLeft:
  8070.             penOrigin.h = centeringFrame->left;
  8071.             break;
  8072.         }
  8073.  
  8074.     ::MoveTo(penOrigin.h, penOrigin.v);
  8075.  
  8076.     GrafPtr    currentPort;
  8077.     ::GetPort(¤tPort);
  8078.     SInt16    savedTxMode = currentPort->txMode;
  8079.     ::TextMode(srcOr);
  8080.     ::DrawString(outputString);
  8081.     ::TextMode(savedTxMode);
  8082.     
  8083.     if ((outColor == kDisabledOutput) && ! deep)
  8084.         {
  8085.         ::PenPat(&qd.gray);
  8086.         ::PenMode(patBic);
  8087.         ::PaintRect(centeringFrame);
  8088.  
  8089.         ::PenNormal();
  8090.         }
  8091.     }
  8092.  
  8093. //
  8094. // GDIterator -----------------------------------------------------
  8095. //
  8096.  
  8097. RgnHandle GDIterator::mSavedClipping = ::NewRgn();
  8098.  
  8099. GDIterator::GDIterator()
  8100.     {
  8101.     this->Setup();
  8102.     }
  8103.  
  8104. GDIterator::~GDIterator()
  8105.     {
  8106.     this->Cleanup();
  8107.     }
  8108.  
  8109. void GDIterator::Setup()
  8110.     {
  8111.     ::GetClip(mSavedClipping);
  8112.     
  8113.     mIteratedYet = FALSE;
  8114.     mCurrentGDHandle = NULL;
  8115.     }
  8116.  
  8117. Boolean GDIterator::More(Boolean& deep)
  8118.     {
  8119.     if (gAGAHasColorQD)
  8120.         {
  8121.         mCurrentGDHandle = this->FindNextValidDevice(mCurrentGDHandle, deep);
  8122.         return (mCurrentGDHandle != NULL);
  8123.         }
  8124.     else
  8125.         {
  8126.         deep = FALSE;
  8127.         return ! mIteratedYet;
  8128.         }
  8129.     }
  8130.  
  8131. void GDIterator::Cleanup()
  8132.     {
  8133.     ::SetClip(mSavedClipping);
  8134.     }
  8135.  
  8136. void GDIterator::ClipFurtherToCurrentDevice()
  8137.     {
  8138.     this->ClipFurtherToDevice(mCurrentGDHandle);
  8139.     }
  8140.  
  8141. GDHandle GDIterator::FindNextValidDevice(GDHandle currentDevice, Boolean& deep)
  8142.     {
  8143.     GDHandle    deviceToTest;
  8144.     GDHandle    deviceFound = NULL;
  8145.     
  8146.     deep = FALSE;
  8147.     
  8148.     if (currentDevice == NULL)
  8149.         deviceToTest = ::GetMainDevice();
  8150.     else
  8151.         deviceToTest = ::GetNextDevice(currentDevice);
  8152.  
  8153.     while ((deviceToTest != NULL) && (deviceFound == NULL))
  8154.         {
  8155.         Boolean    isValidDevice = FALSE;
  8156.         
  8157.         if (::TestDeviceAttribute(deviceToTest, screenDevice))
  8158.             if (::TestDeviceAttribute(deviceToTest, screenActive))
  8159.                 {
  8160.                 isValidDevice = TRUE;
  8161.                 
  8162.                 SInt16    pixelDepth = (**((**deviceToTest).gdPMap)).pixelSize;
  8163.                 Boolean    isColor = ::TestDeviceAttribute(deviceToTest, gdDevType);
  8164.                 
  8165.                 deep = (pixelDepth >= 8) || ((pixelDepth >= 4) && ! isColor);
  8166.                 
  8167.                 deviceFound = deviceToTest;
  8168.                 }
  8169.  
  8170.         if (! isValidDevice)
  8171.             deviceToTest = ::GetNextDevice(deviceToTest);
  8172.         }
  8173.     
  8174.     if (deviceFound != NULL)
  8175.         {
  8176.         ::SetClip(mSavedClipping);
  8177.         this->ClipFurtherToDevice(deviceFound);
  8178.         }
  8179.  
  8180.     return deviceFound;
  8181.     }
  8182.  
  8183. void GDIterator::ClipFurtherToDevice(GDHandle aDevice)
  8184.     {
  8185.     if (aDevice != NULL)
  8186.         {
  8187.         Rect    deviceRect = (**aDevice).gdRect;
  8188.         Point    drTopLeft;
  8189.         Point    drBotRight;
  8190.         
  8191.         ::SetPt(&drTopLeft, deviceRect.left, deviceRect.top);
  8192.         ::SetPt(&drBotRight, deviceRect.right, deviceRect.bottom);
  8193.         
  8194.         ::GlobalToLocal(&drTopLeft);
  8195.         ::GlobalToLocal(&drBotRight);
  8196.         
  8197.         ::SetRect(&deviceRect, drTopLeft.h, drTopLeft.v, drBotRight.h, drBotRight.v);
  8198.         
  8199.         AGAClipFurther(&deviceRect);
  8200.         }
  8201.     }
  8202.  
  8203. //
  8204. // AGABackgroundPaint ------------------------------------------------
  8205. //
  8206.  
  8207. void AGABackgroundPaint(const Rect* backgroundBounds,
  8208.                         Boolean drawFill,
  8209.                         Boolean isModal,
  8210.                         Boolean isActive,
  8211.                         Boolean hasGrowBox)
  8212.     {
  8213.     CleansePen();
  8214.  
  8215.     // Draw in the specified active/inactive state.
  8216.  
  8217.     enum { kBGFill, kBGActiveLight, kBGActiveShadow, kBGInactiveLight, kBGInactiveShadow, kBGNumIndexes };
  8218.  
  8219.     UInt8    colorIndexes[kBGNumIndexes];
  8220.  
  8221.     if (isModal)
  8222.         {
  8223.         colorIndexes[kBGFill] = r2;
  8224.         colorIndexes[kBGActiveLight] = rW;
  8225.         colorIndexes[kBGActiveShadow] = r5;
  8226.         colorIndexes[kBGInactiveLight] = r1;
  8227.         colorIndexes[kBGInactiveShadow] = r4;
  8228.         }
  8229.     else
  8230.         {
  8231.         colorIndexes[kBGFill] = r2;
  8232.         colorIndexes[kBGActiveLight] = rW;
  8233.         colorIndexes[kBGActiveShadow] = r6;
  8234.         colorIndexes[kBGInactiveLight] = r1;
  8235.         colorIndexes[kBGInactiveShadow] = r4;
  8236.         }
  8237.  
  8238.     GDIterator    iter;
  8239.     Boolean        deep;
  8240.  
  8241.     while (iter.More(deep))
  8242.         {
  8243.         Rect    r = *backgroundBounds;
  8244.  
  8245.         if (deep)
  8246.             {
  8247.             ::InsetRect(&r, 1, 1);
  8248.             
  8249.             if (drawFill)
  8250.                 {
  8251.                 ::RGBForeColor(&gAGARamp[colorIndexes[kBGFill]]);
  8252.             
  8253.                 ::PaintRect(&r);
  8254.                 ::MoveTo(r.left - 1, r.bottom);
  8255.                 ::Line(0, 0);
  8256.                 ::MoveTo(r.right, r.top - 1);
  8257.                 ::Line(0, 0);
  8258.                 }
  8259.             
  8260.             if (isActive)
  8261.                 ::RGBForeColor(&gAGARamp[colorIndexes[kBGActiveLight]]);
  8262.             else
  8263.                 ::RGBForeColor(&gAGARamp[colorIndexes[kBGInactiveLight]]);
  8264.  
  8265.             ::MoveTo(r.left - 1, r.bottom - 1);
  8266.             ::LineTo(r.left - 1, r.top - 1);
  8267.             ::LineTo(r.right - 1, r.top - 1);
  8268.             
  8269.             if (isActive)
  8270.                 ::RGBForeColor(&gAGARamp[colorIndexes[kBGActiveShadow]]);
  8271.             else
  8272.                 ::RGBForeColor(&gAGARamp[colorIndexes[kBGInactiveShadow]]);
  8273.  
  8274.             ::MoveTo(r.left, r.bottom);
  8275.             
  8276.             if (hasGrowBox)
  8277.                 {
  8278.                 ::LineTo(r.right - 15, r.bottom);
  8279.                 ::Line(0, -15);
  8280.                 ::Line(15, 0);
  8281.                 }
  8282.             else
  8283.                 ::LineTo(r.right, r.bottom);
  8284.  
  8285.             ::LineTo(r.right, r.top);
  8286.             }
  8287.         else    // 1-bit
  8288.             {
  8289.             if (drawFill)
  8290.                 {
  8291.                 ::RGBBackColor(&gAGARamp[rW]);
  8292.                 ::EraseRect(&r);
  8293.                 }
  8294.             }
  8295.         }
  8296.  
  8297.     CleansePen();
  8298.     }
  8299.  
  8300. //
  8301. // AGAClipFurther ------------------------------------------------
  8302. //
  8303.  
  8304. void AGAClipFurther(Rect* clippingRect)
  8305.     {
  8306.     RgnHandle    oldClip = ::NewRgn();
  8307.     RgnHandle    newClip = ::NewRgn();
  8308.     
  8309.     if ((oldClip != NULL) && (newClip != NULL))
  8310.         {
  8311.         ::GetClip(oldClip);
  8312.         ::RectRgn(newClip, clippingRect);
  8313.  
  8314.         ::SectRgn(oldClip, newClip, newClip);
  8315.         ::SetClip(newClip);
  8316.         
  8317.         ::DisposeRgn(oldClip);
  8318.         ::DisposeRgn(newClip);
  8319.         }
  8320.     }
  8321.  
  8322. //
  8323. // CleansePen ------------------------------------------------
  8324. //
  8325.  
  8326. void CleansePen()
  8327.     {
  8328.     // We use this at the beginning and ending of all drawing methods.
  8329.     // It sets up the pen for our drawing, and it cleans up after us.
  8330.     //
  8331.     // We could require the caller (the MA or PP adapter classes) to
  8332.     // always clean things up only and exactly when their own
  8333.     // particular drawing environment requires, but it's simpler if
  8334.     // we just do it ourself to ensure that our environment is OK for
  8335.     // our needs, and that we leave it in a standard state when done.
  8336.  
  8337.     ::PenNormal();                            // pen size 1,1, solid black pattern, srcOr
  8338.     ::RGBForeColor(&gAGARamp[rB]);            // black fore color
  8339.     ::RGBBackColor(&gAGARamp[rW]);            // white back color
  8340.     gAGAStdSystemStyle.PrepareForDrawing();    // system font 12 point
  8341.     }
  8342.  
  8343.  
  8344. //
  8345. // AGA Defaults ------------------------------------------------
  8346. //
  8347.  
  8348. void SetGrayCouncilDefault(UInt32 itemMask, Boolean turnOn)
  8349.     {
  8350.     if (turnOn)
  8351.         gAGADefaults |= itemMask;
  8352.     else
  8353.         gAGADefaults &= ~itemMask;
  8354.     }
  8355.  
  8356. Boolean TestGrayCouncilDefault(UInt32 itemMask)
  8357.     {
  8358.     return ((gAGADefaults & itemMask) != 0);
  8359.     }
  8360.  
  8361.